ただの健忘録。
build.sbt に以下を追加。
scalacOptions in Global += "-language:experimental.macros"
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value
以下みたいな感じで書く。準クオートで書くprintlnマクロはこんな感じ。
import language.experimental.macros
import scala.reflect.macros.whitebox.Context
object PrintMacro {
def p(msg: String): Unit = macro impl
def impl(c: Context)(msg: c.Expr[String]) = {
import c.universe._
q"""
println(${msg})
"""
}
}
とか、変数名デバッグマクロとか作るときは、構文木作れるreify/spliceが便利。
import language.experimental.macros
import scala.reflect.macros.whitebox.Context
object DebugMacro {
def debug(param: Any): Unit = macro debug_impl
def debug_impl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = {
import c.universe._
val paramRep = show(param.tree)
val paramRepTree = Literal(Constant(paramRep))
val paramRepExpr = c.Expr[String](paramRepTree)
reify { println(paramRepExpr.splice + " = " + param.splice) }
}
}
文字列でプロパティアクセスするマクロとかはこんな感じ。
import language.experimental.macros
import scala.reflect.macros.whitebox.Context
object AccesserMacro {
def accesser(obj: Any, property: String): Any = macro impl
def impl(c: Context)(obj: c.Expr[Any], property: c.Expr[String]) = {
import c.universe._
val Expr(Literal(Constant(propString: String))) = property
Select(obj.tree, TermName(propString))
}
}
Def Macroのドキュメントにも書いてあるけどケースクラスの構造化代入使うと便利。
詳しいマクロやり方は、
http://docs.scala-lang.org/ja/overviews/macros/overview
を見つつScalaDocコメント読むのが良さそう。
StackOverFlowにマクロ職人が沢山いるので検索すると勉強になる。
http://stackoverflow.com/search?tab=votes&q=Scala%20macro
2.11でwhiteboxマクロとblackboxマクロというのが2.11で分かれていたので注意。
http://docs.scala-lang.org/ja/overviews/macros/blackbox-whitebox