Shiva Wu
Shiva Wu

Reputation: 1094

Obtain the field member of the class where the macro is defined in

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

Answers (2)

Shiva Wu
Shiva Wu

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

Volker Stampa
Volker Stampa

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

Related Questions