Reputation: 1094
I'm trying to define a macro in a trait. For example,
trait Macro {
val magic: Int = 1001
def doMagic(x: Int): Int = macro Impl.doMagic
}
object Impl {
def doMagic(c: Context)(x: c.Expr[Int]): c.Expr[Int] = ???
}
What I'm trying to do here is, the doMagic implementation should be able to refer to the field magic
in the trait Macro
, type-safely.
I tried to refer to this by This(c.enclosingClass.asModule.moduleClass)
, but it seems to refer the tree of macro application, which resulting an anonymous class called $iw. So in my understanding the Enclosures is where the macro is being applied, not where it's being defined.
Is there anyway I can do this?
Upvotes: 1
Views: 78
Reputation: 1094
I sorted it out. We should use c.prefix, like
val self = TermName(c.freshName("self"))
c.Expr[T] {
q"""
val $self = ${c.prefix.tree}
...
"""
}
And a self variable can be used to capture the prefix, so it's only evaluated once.
Upvotes: 0
Reputation: 849
This does not answer the question directly, but maybe it helps nonetheless. You could pass the instance as parameter to the macro and to hide this from the caller you could add a corresponding method delegating to doMagic
like this:
trait Macro {
val magic: Int = 1001
def doMagic(m: Macro, x: Int): Int = macro Impl.doMagic
}
object Impl {
def doMagic(context: Context)(m: context.Expr[Macro], x: context.Expr[Int]): context.Expr[Int] = {
import context.universe._
reify(m.splice.magic + x.splice)
}
}
the wrapper-trait:
trait Macro2 extends Macro {
def doMagic2(x: Int): Int = doMagic(this, x)
}
and the caller:
val z = new Macro2 {}
println(z.doMagic2(5))
Upvotes: 1