scala - 从方法符号和主体创建方法定义树

标签 scala reflection macros scala-2.10 scala-macros

有没有方便的方法转 MethodSymbol 进入 Scala 2.10 中方法定义树(即 DefDef )的左侧?

例如,假设我想创建一个宏,该宏将采用 trait 的一个实例,并用一些调试功能包装所有该 trait 的方法。我可以写以下内容:

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

  //...
}

我省去了将这些方法粘贴在一个新的匿名类中,该类实现了 trait 然后实例化该类的无聊工作——你可以找到一个完整的工作示例 here如果你有兴趣。

现在我可以写这个,例如:
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

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

我真正想要的是一个函数,它将为新主体采用方法符号和树并返回 DefDef .我已经开始手写一个,但它涉及很多像这样的繁琐的东西:
List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...)

这很烦人,冗长且容易出错。我是否在新的 Reflection API 中缺少一些更好的方法来做到这一点?

最佳答案

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

您最好的选择可能是遍历 c.enclosingRun.units ,递归到每个 unit.body树木随行。如果您看到 DefDef ,其中有一个 symbol等于你的符号,那么你就到达了目的地。更新。别忘了duplicate重用之前的定义树!

这种技术远非世界上最方便的东西,但它应该有效。

关于scala - 从方法符号和主体创建方法定义树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13767582/

相关文章:

scala - scalatest 检测到故障时如何忽略测试实用程序方法?

scala - 当人们说他们运行 'scala in the backend' 时,他们是在什么情况下谈论的?

java - 有没有办法改变 Spark 中 RDD 的复制因子?

java - 是否可以创建一个空的类加载器?

reflection - F# 如何从装箱的 Map 对象中提取键

c - C 中的宏和前/后增量

c++ - 如何在 C++ 项目中制作宏解析器

vim - 如何在段落后自动插入 <p></p> 标签?

scala - 如何保证Actor的响应时间?

java - 使用反射将未知类的对象添加到 ArrayList