递归地评估 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,您需要用表明它是名为 xInt 的函数的信息重新包装子树。这是一个有效的 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)
    }
  }
}