1

我正在尝试使用反射 API 手动生成 AST,使用 showRaw 给我一些关于所需语法的提示。这段代码:

object myfn extends Function2[ Double, Double, Double ] {
    def apply( x : Double, y : Double ) = x + y
}

val x = 0.0
println( showRaw( reify( myfn( x, x ) ).tree ) )

给出原始 AST 输出:

Apply(Select(Ident(myfn), newTermName("apply")), 
    List(Ident(newTermName("x")), Ident(newTermName("x"))))

将原始输出的文字放回程序中不会编译:

val v = Apply(Select(Ident(myfn), newTermName("apply")), 
    List(Ident(newTermName("x")), Ident(newTermName("x"))))
// ^ doesn't compile

因为 Ident 显然需要一个字符串作为参数。如果我传入字符串“myfn”,那么

val v = Apply(Select(Ident("myfn"), newTermName("apply")), 
    List(Ident(newTermName("x")), Ident(newTermName("x"))))

runtimeMirror( getClass.getClassLoader ).mkToolBox().eval( v )

它编译,但评估在运行时失败

"scala.tools.reflect.ToolBoxError: reflective compilation has failed: 
value apply is not a member of <notype>
[...]

因此,原始 AST 输出中 myfn 的实际类型可能不是字符串,但从 API 文档中看不出它可能是什么。

那么,谁能告诉我如何构建所需的 AST?

4

1 回答 1

1

我的做法略有不同——一个问题是该值x在全球范围内并不为人所知——所以我使用了可以轻松替换的常量值。另外我不知道您myfn是否在相对于eval调用的全局级别上定义。这里的小示例程序现在可以工作了(但是使用最新的 2.10.1-RC3 编译 - 也许已经修复了一些东西?)。

import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox

object myfn extends Function2[Double, Double, Double] {
  def apply(x: Double, y: Double) = x + y
  def printTree {println(showRaw(reify(myfn(1.0, 2.0)).tree))}
}

object ReflectTest extends App {
  myfn.printTree // prints the tree that is used below - myfn is replaced with "myfn"
  val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
  println("result = " + tb.eval(Apply(Select(Ident("myfn"), newTermName("apply")), List(Literal(Constant(1.0)), Literal(Constant(2.0))))))
}

编辑

在下面的评论之后,这里是包含另一个包的调用mypackage,它可能是包含点的任意包路径:

tb.eval(Apply(
  Select(Select(Ident(newTermName("mypackage")), newTermName("myfn")), newTermName("apply")), 
  List(Literal(Constant(1.0)), Literal(Constant(2.0)))))
于 2013-03-12T19:22:43.140 回答