递归地评估Scala抽象语法树

时间:2016-01-26 23:30:08

标签: scala abstract-syntax-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 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

1 个答案:

答案 0 :(得分:0)

自己解决了这个问题。为了在子树上调用toolbox.eval,您需要使用指示它是名为Int x的函数的信息重新包装子树。以下是有效的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)
    }
  }
}