sim*_*905 13 scala scala-macros
如果我有一个宏tranforms
代码如下:
(src: a.b.c.TestEntity) =>
{
z.y.TestTable(None)
}
Run Code Online (Sandbox Code Playgroud)
要匹配该AST的None部分,我可以使用提取器,例如:
object NoneExtractor {
def unapply(t: Tree): Boolean = t match {
case Select(Ident(scala), none) if scala.encoded == "scala" && none.encoded == "None" => true
case _ => false
}
}
Run Code Online (Sandbox Code Playgroud)
因为showRaw
AST的None部分看起来像:
Select(Ident(scala), None)
Run Code Online (Sandbox Code Playgroud)
然而,如果我想编写单元测试,NoneExtractor
我不想编译和重建宏,并在宏编译的项目中托管测试.我想在宏的项目中对提取器进行单元测试,这表明运行时反射是可行的方法:
val t = reify {
(src: a.b.c.TestEntity) =>
{
z.y.TestTable(None)
}
}.tree
Run Code Online (Sandbox Code Playgroud)
然而树是完全不同的,在showRaw
那棵树中看起来像是:
Ident(scala.None)
Run Code Online (Sandbox Code Playgroud)
这对于编写负面测试和检查宏的错误处理来说是个坏消息.您不能使用来自另一个项目的宏为宏编写负面测试,因为代码无法编译(并且您无法使用编译错误调试负面测试).
为什么在编译时反射和运行时反射之间,像None一样基本的表示形式如此不同?有没有办法在宏项目中创建可测试的树片段,这与在编译时反射期间传递给宏的AST相同?
要解决这种不一致问题,您可以在模式匹配中使用即将推出的quasiqoutes 。它们抽象了 AST,因此可以使用两种表示形式(无论如何,AST 是特定于编译器的,Scala 目前是单一编译器语言,但依赖编译器的内部表示形式并不是很好):
case q"_root_.scala.None" => ...
Run Code Online (Sandbox Code Playgroud)
将匹配两个 AST。您还可以创建树,q"_root_.scala.None"
这样您就不必担心表示问题。当 scala 2.11 发布 quasiquotes 时,Reify 将被淘汰。要在 scala 2.10 中使用 quasiquotes,您可以使用Macro heaven。
这是关于 scala quasiquotes 的一个很好的 WIP 指南。
归档时间: |
|
查看次数: |
241 次 |
最近记录: |