从方法符号和主体创建方法定义树 [英] Creating a method definition tree from a method symbol and a body

查看:83
本文介绍了从方法符号和主体创建方法定义树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方便的方法来打开

我已经避免了将这些方法粘贴在实现该特性的新匿名类中,然后实例化该类的无聊工作,您可以找到一个完整的工作示例解决方案

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

您最好的选择可能是遍历c.enclosingRun.units,并在进行时递归到每个unit.body树中.如果看到DefDef(其symbol等于您的符号),则您已经到达目的地.更新.重用之前,请不要忘记duplicate定义树!

该技术远非世界上最方便的方法,但它应该可以工作.

Is there a convenient way to turn a MethodSymbol into the left-hand side of a method definition tree (i.e., a DefDef) in Scala 2.10?

For example, suppose I want to create a macro that will take an instance of a trait and wrap all of that trait's methods with some debugging functionality. I can write the following:

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

  //...
}

I've elided the boring business of sticking these methods in a new anonymous class that implements the trait and then instantiating that class—you can find a complete working example here if you're interested.

Now I can write this, for example:

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

So it works, but only in very simple cases—it won't if the trait has methods with parameter lists, with access modifiers, annotations, etc.

What I really want is a function that will take a method symbol and a tree for the new body and return a DefDef. I've started writing one by hand, but it involves a lot of fiddly stuff like this:

List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...)

Which is annoying, verbose, and error-prone. Am I missing some nicer way to do this in the new Reflection API?

解决方案

To the best of my knowledge, there's no standard way to go from a symbol to a defining tree.

Your best bet would probably be to iterate through c.enclosingRun.units, recursing into each of the unit.body trees as you go. If you see a DefDef, which has a symbol equal to your symbol, then you've reached your destination. upd. Don't forget to duplicate the defining tree before reusing it!

This technique is far from being the most convenient thing in the world, but it should work.

这篇关于从方法符号和主体创建方法定义树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆