Skip to content

Instantly share code, notes, and snippets.

@seraphr
Created February 18, 2014 10:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seraphr/9068388 to your computer and use it in GitHub Desktop.
Save seraphr/9068388 to your computer and use it in GitHub Desktop.
scalaのdefマクロでコンストラクタ呼び出しコード生成
import scala.reflect.macros.Context
import scala.language.experimental.macros
object InitializeMacro{
def init[T, A, B](a: A, b: B) = macro initImpl[T, A, B]
def initImpl[T: c.WeakTypeTag, A: c.WeakTypeTag ,B: c.WeakTypeTag](c: Context)(a: c.Expr[A], b: c.Expr[B]): c.Expr[T] = {
import c.universe._
val tType = implicitly[WeakTypeTag[T]].tpe
val tA = implicitly[WeakTypeTag[A]].tpe
val tB = implicitly[WeakTypeTag[B]].tpe
val tConstructors = tType.members.filter(_.isMethod).map(_.asMethod).filter(_.isConstructor)
val tConstructorsParams = tConstructors.map(_.paramss.flatten.map(_.typeSignature))
val tConstructorSymbol = tConstructorsParams.find{tParams =>
tParams.size == 2 && tA <:< tParams(0) && tA <:< tParams(0) && tB <:< tParams(1)
} match {
case None => c.abort(c.enclosingPosition, s"type ${tType} don't have target constructor")
case Some(s) => s
}
val newT = Select(New(Ident(tType.typeSymbol)), nme.CONSTRUCTOR)
val newTWithParams = Apply(newT, List(a.tree, b.tree))
c.info(c.enclosingPosition, s"Generated code: ${c.universe.show(newTWithParams)}", force = false)
c.Expr(newTWithParams)
}
}
class Initializer[T]{
type _InitResult[T] = T
def use[A, B](a: A, b: B): T = macro InitializeMacro.initImpl[T, A, B]
}
def init[T] = new Initializer[T]
case class Hoge(a: String, b: Int)
scala> init[Hoge].use("hoge", 10)
res2: Hoge = Hoge(hoge,10)
scala> init[Hoge].use("hoge", "hoge")
<console>:15: error: type Hoge don't have target constructor
init[Hoge].use("hoge", "hoge")
^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment