Skip to content

Instantly share code, notes, and snippets.

@mandubian
Last active December 19, 2015 17:48
Show Gist options
  • Save mandubian/5993771 to your computer and use it in GitHub Desktop.
Save mandubian/5993771 to your computer and use it in GitHub Desktop.
I want to call recursively the macro mkObject in itself... But it can't compile because the @Body trick doesn't accept an instance generated by mkObject itself...
//The huge error
[error]
[error] while compiling: /Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/core/src/main/scala/Test.scala
[error] during phase: pickler
[error] library version: version 2.10.0
[error] compiler version: version 2.10.0
[error] reconstructed args: -d /Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/core/target/scala-2.10/classes -bootclasspath /Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/JObjC.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/classes:/Users/pvo/.sbt/boot/scala-2.10.0/lib/scala-library.jar -classpath /Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/core/target/scala-2.10/classes:/Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/macros/target/scala-2.10/classes:/Users/pvo/.ivy2/cache/org.scala-lang.macro-paradise/scala-reflect/jars/scala-reflect-2.10.2-SNAPSHOT.jar
[error]
[error] last tree to typer: Literal(Constant(10))
[error] symbol: null
[error] symbol definition: null
[error] tpe: Int(10)
[error] symbol owners:
[error] context owners: anonymous class $anon -> value <local Workaround> -> class Workaround -> value foo -> object Test -> package <empty>
[error]
[error] == Enclosing template or block ==
[error]
[error] ClassDef( // class $anon extends Workaround
[error] 0
[error] "$anon"
[error] []
[error] Template( // val <local $anon>: <notype>, tree.tpe=Workaround
[error] "Test.Workaround.Workaround" // parents
[error] ValDef(
[error] private
[error] "_"
[error] <tpt>
[error] <empty>
[error] )
[error] DefDef( // def <init>(): Workaround
[error] <method> <triedcooking>
[error] "<init>"
[error] []
[error] List(Nil)
[error] <tpt> // tree.tpe=Workaround
[error] Block( // tree.tpe=Unit
[error] Apply( // def <init>(): Workaround in class Workaround, tree.tpe=Workaround
[error] $anon.super."<init>" // def <init>(): Workaround in class Workaround, tree.tpe=()Workaround
[error] Nil
[error] )
[error] ()
[error] )
[error] )
[error] )
[error] )
[error]
[error] == Expanded type of tree ==
[error]
[error] ConstantType(value = Constant(10))
[error]
[error] uncaught exception during compilation: java.lang.AssertionError
[trace] Stack trace suppressed: run last core/compile:compile for the full output.
[error] (core/compile:compile) java.lang.AssertionError: assertion failed:
[error] while compiling: /Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/core/src/main/scala/Test.scala
[error] during phase: pickler
[error] library version: version 2.10.0
[error] compiler version: version 2.10.0
[error] reconstructed args: -d /Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/core/target/scala-2.10/classes -bootclasspath /Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/JObjC.jar:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/classes:/Users/pvo/.sbt/boot/scala-2.10.0/lib/scala-library.jar -classpath /Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/core/target/scala-2.10/classes:/Users/pvo/zenexity/work/macrotest/sbt-example-paradise210/macros/target/scala-2.10/classes:/Users/pvo/.ivy2/cache/org.scala-lang.macro-paradise/scala-reflect/jars/scala-reflect-2.10.2-SNAPSHOT.jar
[error]
[error] last tree to typer: Literal(Constant(10))
[error] symbol: null
[error] symbol definition: null
[error] tpe: Int(10)
[error] symbol owners:
[error] context owners: anonymous class $anon -> value <local Workaround> -> class Workaround -> value foo -> object Test -> package <empty>
[error]
[error] == Enclosing template or block ==
[error]
[error] ClassDef( // class $anon extends Workaround
[error] 0
[error] "$anon"
[error] []
[error] Template( // val <local $anon>: <notype>, tree.tpe=Workaround
[error] "Test.Workaround.Workaround" // parents
[error] ValDef(
[error] private
[error] "_"
[error] <tpt>
[error] <empty>
[error] )
[error] DefDef( // def <init>(): Workaround
[error] <method> <triedcooking>
[error] "<init>"
[error] []
[error] List(Nil)
[error] <tpt> // tree.tpe=Workaround
[error] Block( // tree.tpe=Unit
[error] Apply( // def <init>(): Workaround in class Workaround, tree.tpe=Workaround
[error] $anon.super."<init>" // def <init>(): Workaround in class Workaround, tree.tpe=()Workaround
[error] Nil
[error] )
[error] ()
[error] )
[error] )
[error] )
[error] )
[error]
[error] == Expanded type of tree ==
[error]
[error] ConstantType(value = Constant(10))*/
// Here is the generated class:
{
class Workaround extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
@new body({
class Workaround extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
@new body(4) <macro> def y = Macros.selFieldImpl;
@new body(10) <macro> def z = Macros.selFieldImpl
};
{
class $anon extends Workaround {
def <init>() = {
super.<init>();
()
};
<empty>
};
new $anon()
}
}) <macro> def x = Macros.selFieldImpl
};
{
class $anon extends Workaround {
def <init>() = {
super.<init>();
()
};
<empty>
};
new $anon()
}
}
import scala.reflect.macros.Context
// uses the technique described in:
// http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros
class Helper[C <: Context](val c: C) extends QuasiquoteCompat {
import c.universe._
def mkObject(xs: c.Tree*): c.Tree = {
val fields = xs.toList map {
case q"${_}(${Literal(Constant(name: String))}).->[${_}](${tup}(..$value))" =>
// Here I call recursively the macro and put the result in @body
val r = mkObject(value:_*)
val res = q"""
@body($r) def ${newTermName(name)} = macro Macros.selFieldImpl
"""
res
case q"${_}(${Literal(Constant(name: String))}).->[${_}]($value)" =>
q"""
@body($value) def ${newTermName(name)} = macro Macros.selFieldImpl
"""
}
val r = q"""class Workaround {
..$fields
}; new Workaround{}"""
println("r:"+r)
r
}
}
import language.experimental.macros
import scala.reflect.macros.Context
import scala.annotation.StaticAnnotation
class body(tree: Any) extends StaticAnnotation
object Macros {
def selFieldImpl(c: Context) = {
val field = c.macroApplication.symbol
val bodyAnn = field.annotations.filter(_.tpe <:< c.typeOf[body]).head
c.Expr[Any](bodyAnn.scalaArgs.head)
}
def mkObject(xs: Any*) = macro mkObjectImpl
def mkObjectImpl(c: Context)(xs: c.Expr[Any]*) = {
val helper = new Helper[c.type](c)
c.Expr[Any](helper.mkObject(xs.map(_.tree):_*))
}
}
import scala.language.experimental.macros
import scala.reflect.macros.Context
object Test extends App {
val foo = Macros.mkObject("x" -> ("y" -> 4, "z" -> 10))
println(foo.x.y)
}
// Here is the generated class:
{
class Workaround extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
@new body({
class Workaround extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
@new body(4) <macro> def y = Macros.selFieldImpl;
@new body(10) <macro> def z = Macros.selFieldImpl
};
{
class $anon extends Workaround {
def <init>() = {
super.<init>();
()
};
<empty>
};
new $anon()
}
}) <macro> def x = Macros.selFieldImpl
};
{
class $anon extends Workaround {
def <init>() = {
super.<init>();
()
};
<empty>
};
new $anon()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment