Scala compiler plugin
Scala pattern matching involves use of either case class or extractor.
When extractor needs parameters to be created, it should be declared as stable identifier before match
block. e.g. With regular expression matching:
val Letter = "[a-zA-Z]+".r
"String" match {
case Letter ⇒ true
}
Match component included in this plugin provides syntax ~(extractorFactory[, bindings])
for rich pattern matching.
Consider following extractor, instantiated with one parameter:
case class Regex(e: String) {
lazy val re = e.r
def unapplySeq(target: Any): Option[List[String]] = re.unapplySeq(target)
}
Then provided rich syntax can be used as following:
str match {
case ~(Regex("^a.*")) ⇒ 1 // no binding
case ~(Regex("# ([A-Z]+).*"), a) ⇒ 2
// if str == "# BCD123", then a = "BCD"
case ~(Regex("([0-9]+);([a-z]+)"), (a, b)) ⇒ 3
// if str == "234;xyz", then a = "234" and b = "xyz"
case _ ⇒ 4
}
It will be refactored by plugin, so that required stable identifiers will be available for matching:
val Xtr1 = Regex("^a.*")
// ...
str match {
case Xtr1 ⇒ 1 // no binding
// ...
}
This plugin is currently published as 1.0.14-SNAPSHOT
on repository https://raw.github.com/applicius/mvn-repo/master/snapshots/
.
If you have another
~
symbol, it will have to be renamed atimport pkg.{ ~ ⇒ renamed }
.
Scalac plugin can be used with SBT project, using its compiler plugins support:
autoCompilerPlugins := true
addCompilerPlugin("org.eu.acolyte" %% "scalac-plugin" % "VERSION")
scalacOptions += "-P:acolyte:debug" // Optional
Maven scala plugin supports compiler plugin, so you can do:
<project>
<!-- ... -->
<build>
<!-- ... -->
<plugings>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<!-- ... version -->
<configuration>
<!-- ... -->
<args><!-- Optional: enable debug -->
<arg>-P:acolyte:debug</arg>
</args>
<compilerPlugins>
<compilerPlugin>
<groupId>org.eu.acolyte</groupId>
<artifactId>scalac-plugin_2.10</artifactId>
<version>VERSION</version>
</compilerPlugin>
</compilerPlugins>
</configuration>
</plugin>
</plugins>
</build>
</project>
There is few option for this plugin.
-P:acolyte:debug
: Display debug while compiling with (e.g. refactored match code).
As match component refactors match
AST when ~(…, …)
is used, then if there is compilation error around that location will be mentioned as /path/to/file.scala#refactored-match-M
(with M
informational index of refactored match).
If there is an error with given extractor factory, you will get something like:
[error] /path/to/file.scala#refactored-match-M:1: Compilation error.
[error] Error details.
[error] val Xtr1 = B() // generated from ln L, col C
Comment // generated from ln L, col C
indicates location in original code, before it gets refactored.
If there result from given extractor factory is not a valid extract, it will raise:
[error] /path/to/file.scala#refactored-match-M:1: value Xtr0 is not a case class constructor, nor does it have an unapply/unapplySeq method
[error] case Xtr1((a @ _)) => Nil // generated from ln L, col C