Skip to content

Instantly share code, notes, and snippets.

@travisbrown
Last active December 19, 2015 17:49
Show Gist options
  • Save travisbrown/5994377 to your computer and use it in GitHub Desktop.
Save travisbrown/5994377 to your computer and use it in GitHub Desktop.
Tested only in Paradise 2.11.0-SNAPSHOT.
import scala.annotation.StaticAnnotation
import scala.collection.mutable.{ Map => MMap }
import scala.language.experimental.macros
import scala.reflect.macros.Context
class body(tree: Any) extends StaticAnnotation
object Macros {
val trees = MMap.empty[String, c.Tree forSome { val c: Context }]
def selFieldImpl(c: Context) = {
import c.universe._
val field = c.macroApplication.symbol
field.annotations.find(_.tpe <:< c.typeOf[body]).map(_.scalaArgs) match {
case Some(Literal(Constant(name: String)) :: _) =>
c.Expr[Any](trees(name).asInstanceOf[c.universe.Tree])
}
}
def mkObject(xs: Any*) = macro mkObjectImpl
def mkObjectImpl(c: Context)(xs: c.Expr[Any]*) = {
import c.universe._
def mkTree(xs: List[c.Tree]): c.Tree = {
val fields = xs.map {
case q"${_}(${Literal(Constant(k: String))}).->[${_}]($v)" => k -> v
}.map {
case (k, q"${tup}(..$nested)") => k -> mkTree(nested)
case (k, v) => k -> v
}.map {
case (name, body) =>
val bodyName = c.fresh("body")
trees(bodyName) = body
q"@body($bodyName) def ${newTermName(name)} = macro Macros.selFieldImpl"
}
q"class Workaround { ..$fields }; new Workaround {}"
}
c.Expr[Any](mkTree(xs.map(_.tree).toList))
}
}
import scala.language.reflectiveCalls
@playbyexample-admin
Copy link

Might be ugly but I would't have thought about tricking the @Body trick with a literal and building a mutable map based on c.Tree forSome { val c: Context } ;)
Great effort!

@travisbrown
Copy link
Author

Thanks! It's essentially the same trick that I use here, except that you don't need the Dynamic stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment