我正在尝试使用反射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显然需要String作为参数。 如果我传入字符串“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的实际类型可能不是String,但是从API文档中可能看不出它是什么。
那么,谁能告诉我如何构建所需的AST?
答案 0 :(得分: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)))))