【发布时间】:2021-02-12 14:55:17
【问题描述】:
我在运行时无法构建正确的 Scala (2.13.3) 语法树。假设我们定义了以下类。
class Foo(x: Int)
我想为以下代码行构建语法树。
new Foo(1)
作为参考,我们可以使用ru.reify 生成正确的语法树。我们也可以输入 check 这棵树来确认它是有效的。
val expectedTree = ru.reify {
new Foo(1)
}
println(ru.showRaw(expectedTree))
// Apply(
// Select(
// New(Ident(my.package.Foo)), <-- What does Ident hold here?
// termNames.CONSTRUCTOR
// ),
// List(
// Literal(Constant(1))
// )
// )
val toolbox = mirror.mkToolBox()
toolbox.typecheck(expectedTree).tpe
// my.package.Foo
但是,如果我不知道如何从头开始正确编码相同的语法树。以下是我的初步尝试。我也用TermName而不是TypeName尝试了同样的事情,看到了同样的结果。
import ru._
val actualTree = Apply(
Select(
New(Ident(TypeName("my.package.Foo"))),
termNames.CONSTRUCTOR
),
List(
Literal(Constant(1))
)
)
println(ru.showRaw(actualTree))
// Apply(
// Select(
// New(Ident(TypeName("my.package.Foo"))), <-- Ident holds a TypeName
// termNames.CONSTRUCTOR
// ),
// List(
// Literal(Constant(1))
// )
// )
val toolbox = mirror.mkToolBox()
toolbox.typecheck(actualTree).tpe
// ToolBoxError: reflective typecheck has failed: not found: type my.package.Foo
actualTree 显然无效,因为它不进行类型检查。如果我们检查打印输出,我们可以看到Ident 在expectedTree 和actualTree 之间似乎不同。
从 API 看来,Ident 似乎必须包含一个 Name 对象,但我无法确定此处需要哪种名称。此外,expectedTree 的打印输出并不表明Ident 持有Name。这是另一种Ident吗?手动构造 new Foo(1) 的 AST 的正确代码是什么?
编辑: 我被要求提供有关为什么 quasiquotes 和/或 reify 对我的用例不起作用的信息。简短的回答是:这是自动编程的研究技术。
研究任务是仅使用测试套件来合成正确的。我正在实现the recently published method called "Code Building Genetic Programming" 的Scala 版本。
我了解在典型反射用例中对手动构建的警告,但我相信其他构建方法需要一些关于程序/AST 在开发时应该是什么的概念。
【问题讨论】:
标签: scala reflection abstract-syntax-tree scala-reflect