AST Transformation对象如何工作?

rsa*_*san 2 recursion scala

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

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

例如,如果我有这个AST:

def foo = {
 true
}
Run Code Online (Sandbox Code Playgroud)

要么

def foo = true
Run Code Online (Sandbox Code Playgroud)

并希望将其转化为

def foo = {
 println("foo")
 true
}
Run Code Online (Sandbox Code Playgroud)

转换函数应该如何显示.在这一点上,我有这样的事情:

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"))))
Run Code Online (Sandbox Code Playgroud)

但是不起作用,说实话我只是应用我在示例中看到的但却无法弄清楚树是如何构建的."傻瓜"的解释将不胜感激.

[编辑]

Senia的例子很不错,但是当我有一个更复杂的树时,我仍然感到困惑:

imports bla.bla
class MyObject{

  val x = 0
  def foo = true
  def foo2 = { 1 }
}
object MyObject
Run Code Online (Sandbox Code Playgroud)

预期结果:

import bla.bla
class MyObject{

  val x = 0
  def foo = { println("foo"); true }
  def foo2 = { println("foo"); 1 }
}
object MyObject
Run Code Online (Sandbox Code Playgroud)

sen*_*nia 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(())))
Run Code Online (Sandbox Code Playgroud)

没有外部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)))
Run Code Online (Sandbox Code Playgroud)

所以你的rhs变量不是Block.

所以,你应该更换//Manage functions without block使用Block(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)
}
Run Code Online (Sandbox Code Playgroud)

测试:

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
}
Run Code Online (Sandbox Code Playgroud)

UPD:

super.transform调用父实现.请参阅代码的内部实现.