Created
February 18, 2014 10:36
-
-
Save seraphr/9068388 to your computer and use it in GitHub Desktop.
scalaのdefマクロでコンストラクタ呼び出しコード生成
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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