2

有人可以帮我掌握允许在 scala 中修改 AST 的转换对象吗?

网络上有很多例子,但我很难理解递归是如何发生的。

例如,如果我有这个 AST:

def foo = {
 true
}

或者

def foo = true

并想将其转换为

def foo = {
 println("foo")
 true
}

变换函数应该是什么样子。在这一点上,我有这样的事情:

override def transform(tree: Tree) = tree match {
 case defdef @ DefDef(_,_,_,_,_,rhs) => rhs match{
   case b: Block => treeCopy.Block(b, createPrintln :: b.stats, b.expr)           
   case _ => //Manage functions without block
 }
 case t => super.transform(t)
}

private def createPrintln = Apply(Select(Ident("System.out"), newTermName("println")), List(Literal(Constant("foo"))))

但不起作用,老实说,我只是应用我在示例中看到的内容,但无法弄清楚树是如何构建的。“傻瓜”的解释将不胜感激。

[编辑]

Senia 的例子很好,但是当我有一个更复杂的树时我仍然卡住了:

imports bla.bla
class MyObject{

  val x = 0
  def foo = true
  def foo2 = { 1 }
}
object MyObject

预期结果:

import bla.bla
class MyObject{

  val x = 0
  def foo = { println("foo"); true }
  def foo2 = { println("foo"); 1 }
}
object MyObject
4

1 回答 1

5

您的原件Tree如下所示:

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> showRaw{ reify { def foo = { true } }.tree }
res0: String = Block(List(DefDef(Modifiers(), newTermName("foo"), List(), List(), TypeTree(), Literal(Constant(true)))), Literal(Constant(())))

没有外部Block

scala> showRaw{ reify { def foo = { true } }.tree match { case Block(List(defdef), _) => defdef } }
res1: String = DefDef(Modifiers(), newTermName("foo"), List(), List(), TypeTree(), Literal(Constant(true)))

所以你的rhs变量不是Block.

所以你应该替换//Manage functions without blockBlock(createPrintln, t)

我猜你的transform方法应该返回DefDef,而不是Block

def addPrintln(t: Tree): Block = t match {
  case b :Block => treeCopy.Block(b, createPrintln :: b.stats, b.expr)
  case t => Block(createPrintln, t)
}

override def transform(tree: Tree) = tree match {
  case defdef @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => 
    treeCopy.DefDef(defdef, mods, name, tparams, vparamss, tpt, addPrintln(rhs))
  case t => super.transform(t)
}

测试:

scala> def createPrintln = Apply(Select(Ident("System.out"), newTermName("println")), List(Literal(Constant("foo"))))
createPrintln: reflect.runtime.universe.Apply

scala> def addPrintln(t: Tree): Block = t match {
     |   case b :Block => treeCopy.Block(b, createPrintln :: b.stats, b.expr)
     |   case t => Block(createPrintln, t)
     | }
addPrintln: (t: reflect.runtime.universe.Tree)reflect.runtime.universe.Block

scala> def transform(tree: Tree) = tree match {
     |   case defdef @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
     |     treeCopy.DefDef(defdef, mods, name, tparams, vparamss, tpt, addPrintln(rhs))
     | }
transform: (tree: reflect.runtime.universe.Tree)reflect.runtime.universe.DefDef

scala> val defdef = reify { def foo = { true } }.tree match { case Block(List(defdef), _) => defdef }
defdef: reflect.runtime.universe.Tree = def foo = true

scala> transform(defdef )
res0: reflect.runtime.universe.DefDef =
def foo = {
  System.out.println("foo");
  true
}

更新:

super.transform调用父实现。代码见内部实现

于 2013-05-08T06:17:01.393 回答