从方法符号和正文创建方法定义树

Tra*_*own 8 reflection macros scala scala-2.10 scala-macros

有没有一种方便的方法可以在Scala 2.10中将MethodSymbol方法定义树(即a DefDef)的左侧转换为?

例如,假设我想创建一个宏来获取特征的实例,并用一些调试功能包装所有特征的方法.我可以写下面的内容:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object WrapperExample {
  def wrap[A](a: A): A = macro wrap_impl[A]

  def wrap_impl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = {
    import c.universe._

    val wrapped = weakTypeOf[A]
    val f = Select(reify(Predef).tree, "println")

    val methods = wrapped.declarations.collect {
      case m: MethodSymbol if !m.isConstructor => DefDef(
        Modifiers(Flag.OVERRIDE),
        m.name,
        Nil, Nil,
        TypeTree(),
        Block(
          Apply(f, c.literal("Calling: " + m.name.decoded).tree :: Nil),
          Select(a.tree, m.name)
        )
      )
    }.toList

  //...
}
Run Code Online (Sandbox Code Playgroud)

我已经省去了无聊的业务,将这些方法粘贴在一个新的匿名类中,该类实现了特性,然后实例化了该类 - 如果你感兴趣的话,你可以在这里找到一个完整的工作示例.

现在我可以写这个,例如:

scala> trait X { def foo = 1; def bar = 'a }
defined trait X

scala> val x = new X {}
x: X = $anon$1@15dd533

scala> val w: X = WrapperExample.wrap[X](x)
w: X = $1$$1@27c3a4a3

scala> w.foo
Calling: foo
res0: Int = 1

scala> w.bar
Calling: bar
res1: Symbol = 'a
Run Code Online (Sandbox Code Playgroud)

所以它可以工作,但只是在非常简单的情况下 - 如果特征具有带参数列表的方法,具有访问修饰符,注释等,则不会.

我真正想要的是一个函数,它将为新主体采用方法符号和树并返回一个DefDef.我已经开始手工编写,但它涉及很多这样的繁琐的东西:

List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...)
Run Code Online (Sandbox Code Playgroud)

这是烦人的,冗长的,容易出错的.我在新的Reflection API中错过了一些更好的方法吗?

Eug*_*ako 4

据我所知,从符号到定义树没有标准的方法。

您最好的选择可能是迭代,在执行时c.enclosingRun.units递归到每棵树。unit.body如果您看到DefDef,其中的 等于symbol您的符号,那么您已到达目的地。更新。duplicate在重用之前不要忘记定义树!

这项技术远不是世界上最方便的事情,但它应该有效。