12

我说“实时代码”是因为我的意思不是来自文本源文件或源字符串,而是来自 partialFunctions / lambdas。(我知道Ruby1.8的parseTree和C# linq可以做到)

考虑一个偏函数 f:

val f = (i: Int, j: Int) => (i + j) * 2

我希望有一些工具可以像这样工作:

getBodyAstFrom(f) //=> (Infix('*'), (Infix('+'), Id('i'), Id('j')), Val('2'))

我不在乎语义的东西(上下文解析和隐式太复杂,对我来说没有必要),我只需要来自实时代码的语法树,有可能吗?

检查其他人的代码可能会出现问题,但我自己的代码呢?以下事情可能吗?

val f = AstFunction(i: Int, j: Int){(i + j) * 2}
f(5, 6) //=> 22
f.ast   //=> (Infix('*'), (Infix('+'), Id('i'), Id('j')), Val('2'))

似乎需要对编译器进行一些黑客攻击,嗯...

4

1 回答 1

17

编译器本身是一个库,您可以调用它。事实上,这就是 REPL 的工作方式。但是,虽然您可以为一串代码获取树(在不同阶段),但您无法为已编译的代码获取它。

当然,除非您使用可以随时更改或干脆不复存在的实验性材料。在这种情况下,您可以尝试:

scala.reflect.Code.lift(f).tree

并得到:

res17: scala.reflect.Tree = Select(Select(Select(Ident(Field(line26$object,PrefixedType(ThisType(RootSymbol),Class(line26$object)))),Field($iw,PrefixedType(ThisType(Class(line26$object)),Class($iw)))),Field($iw,PrefixedType(ThisType(Class($iw)),Class($iw)))),Method(f,PolyType(List(),List(),AppliedType(PrefixedType(ThisType(Class(scala)),Class(scala.Function2)),List(PrefixedType(ThisType(Class(scala)),Class(scala.Int)), PrefixedType(ThisType(Class(scala)),Class(scala.Int)), PrefixedType(ThisType(Class(scala)),Class(scala.Int)))))))

是否有帮助...您可能想查看 Miguel Garcia 的“ The Scala Compiler Corner ”。

于 2009-12-26T16:05:05.470 回答