递归地评估 Scala 抽象语法树
evaluate Scala abstract syntax tree recursively
假设我有一个 lambda,我使用 reify 将它转换成一个包裹在树上的 Expr。例如
val expr = reify{x: Int => 3*(4+x)}
我可以针对特定的 x 进行如下评估
val toolbox = currentMirror.mkToolBox()
val fun = toolbox.eval(expr.tree).asInstanceOf[Int => Int]
println(fun(10))
我的目标是打印出整棵树,并用每个子表达式的值进行注释。如何确定所有子表达式及其值?例如判断x为10时有子表达式
(4+x)
计算结果为 14。Traverser class 让我访问树中的每个节点,但我不知道如何计算每个节点的子树。
例如,使用以下
class TestTraverser extends Traverser {
override def traverse(tree: Tree): Unit = {
val toolbox = currentMirror.mkToolBox()
tree match {
case app @ Apply(fun, args) =>
val f = toolbox.eval(app.fun)
case _ =>
}
super.traverse(tree)
}
}
呼叫
new TestTraverser().traverse(expr.tree)
导致此异常
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
ambiguous reference to overloaded definition,
both method * in class Int of type (x: Char)Int
and method * in class Int of type (x: Byte)Int
match expected type Any
我自己解决了这个问题。为了在子树上调用 toolbox.eval
,您需要用表明它是名为 x
的 Int
的函数的信息重新包装子树。这是一个有效的 Traverser
示例。
class WorkingTraverser extends Traverser {
val toolbox = currentMirror.mkToolBox()
override def traverse(tree: Tree): Unit = {
tree match {
case app @ Apply(fun, args) =>
val newfun = Function(List(ValDef(Modifiers(PARAM), TermName("x"), Ident(TypeName("Int")), EmptyTree)), Apply(app.fun, app.args))
val f = toolbox.eval(newfun)
val f2 = f.asInstanceOf[Int => Int]
println(app.fun + "(" + app.args + ")" + " evaluates to " + f2(10))
super.traverse(fun)
super.traverseTrees(args)
case _ => super.traverse(tree)
}
}
}
假设我有一个 lambda,我使用 reify 将它转换成一个包裹在树上的 Expr。例如
val expr = reify{x: Int => 3*(4+x)}
我可以针对特定的 x 进行如下评估
val toolbox = currentMirror.mkToolBox()
val fun = toolbox.eval(expr.tree).asInstanceOf[Int => Int]
println(fun(10))
我的目标是打印出整棵树,并用每个子表达式的值进行注释。如何确定所有子表达式及其值?例如判断x为10时有子表达式
(4+x)
计算结果为 14。Traverser class 让我访问树中的每个节点,但我不知道如何计算每个节点的子树。
例如,使用以下
class TestTraverser extends Traverser {
override def traverse(tree: Tree): Unit = {
val toolbox = currentMirror.mkToolBox()
tree match {
case app @ Apply(fun, args) =>
val f = toolbox.eval(app.fun)
case _ =>
}
super.traverse(tree)
}
}
呼叫
new TestTraverser().traverse(expr.tree)
导致此异常
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
ambiguous reference to overloaded definition,
both method * in class Int of type (x: Char)Int
and method * in class Int of type (x: Byte)Int
match expected type Any
我自己解决了这个问题。为了在子树上调用 toolbox.eval
,您需要用表明它是名为 x
的 Int
的函数的信息重新包装子树。这是一个有效的 Traverser
示例。
class WorkingTraverser extends Traverser {
val toolbox = currentMirror.mkToolBox()
override def traverse(tree: Tree): Unit = {
tree match {
case app @ Apply(fun, args) =>
val newfun = Function(List(ValDef(Modifiers(PARAM), TermName("x"), Ident(TypeName("Int")), EmptyTree)), Apply(app.fun, app.args))
val f = toolbox.eval(newfun)
val f2 = f.asInstanceOf[Int => Int]
println(app.fun + "(" + app.args + ")" + " evaluates to " + f2(10))
super.traverse(fun)
super.traverseTrees(args)
case _ => super.traverse(tree)
}
}
}