将Scala AST减少到最简单的等效AST

时间:2016-04-01 03:33:17

标签: scala macros abstract-syntax-tree

假设我想编写一个需要知道(在编译时)它的参数的实际值的宏。如果用户以这种方式调用它:

mymacro(42)

然后传递给宏的树将是Literal(Constant(42)),宏可以像这样模式匹配:

tree match { case Literal(Constant(x: Int)) => x }

希望知道任意表达式的值:

mymacro(40 + numWindowsOpen())  // not allowed; macro should fail at compile time

但是,我想允许这样的表达式:

val answer = 42   // val is immutable
mymacro(answer)

树是Ident(TermName("answer")),或者像这样:

mymacro(40 + 2)

树为Apply(Select(Literal(Constant(40)), TermName("$plus")), List(Literal(Constant(2))))

问题:有没有办法将上述所有三个静态可计算的例子简化为相同的表格?

我的主张是,所有三棵树在某种意义上都是等同于

我知道在编译时可以评估一棵树,例如:

val tree = q"40 + 2"

import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val toolbox = runtimeMirror(getClass.getClassLoader).mkToolBox()
toolbox.eval(tree)  // returns 42

这可能是一个选项,但它有点不能令人满意,因为表达式中的任何副作用都将在编译时执行。实际上,它甚至可能返回40 + numWindowsOpen()树的值,这直觉上并不是静态值。

0 个答案:

没有答案