作为宏的一部分,我想操纵部分函数的大小写定义 .
为此,我使用Transformer来操作partial函数的case定义,并使用Traverser来检查case定义的模式:
def myMatchImpl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context)
(expr: c.Expr[A])(patterns: c.Expr[PartialFunction[A, B]]): c.Expr[B] = {
import c.universe._
val transformer = new Transformer {
override def transformCaseDefs(trees: List[CaseDef]) = trees map {
case caseDef @ CaseDef(pattern, guard , body) => {
// println(show(pattern))
val traverser = new Traverser {
override def traverse(tree: Tree) = tree match {
// match against a specific pattern
}
}
traverser.traverse(pattern)
}
}
}
val transformedPartialFunction = transformer.transform(patterns.tree)
c.Expr[B](q"$transformedPartialFunction($expr)")
}
现在让我们假设,我想要匹配的有趣数据由类Data(它是对象Example的一部分)表示:
case class Data(x: Int, y: String)
现在调用下面示例中的宏
abstract class Foo
case class Bar(data: Data) extends Foo
case class Baz(string: String, data: Data) extends Foo
def test(foo: Foo) = myMatch(foo){
case Bar(Data(x,y)) => y
case Baz(_, Data(x,y)) => y
}
部分函数的大小写定义的模式由编译器转换如下(Foo,Bar和Baz类也是对象Example的成员):
(data: Example.Data)Example.Bar((x: Int, y: String)Example.Data((x @ _), (y @ _)))
(string: String, data: Example.Data)Example.Baz(_, (x: Int, y: String)Example.Data((x @ _), (y @ _)))
这是在上面的宏中使用show打印模式的结果(使用show),原始抽象语法树(使用showRaw打印)如下所示:
Apply(TypeTree().setOriginal(Select(This(newTypeName("Example")), Example.Bar)), List(Apply(TypeTree().setOriginal(Select(This(newTypeName("Example")), Example.Data)), List(Bind(newTermName("x"), Ident(nme.WILDCARD)), Bind(newTermName("y"), Ident(nme.WILDCARD))))))
Apply(TypeTree().setOriginal(Select(This(newTypeName("Example")), Example.Baz)), List(Ident(nme.WILDCARD), Apply(TypeTree().setOriginal(Select(This(newTypeName("Example")), Example.Data)), List(Bind(newTermName("x"), Ident(nme.WILDCARD)), Bind(newTermName("y"), Ident(nme.WILDCARD))))))
如何编写与这些树匹配的模式引用?
2 回答
首先,有一种特殊用于CaseDefs的quasiquotes,称为
cq
:其次,你应该使用
pq
来解构模式:如果您对用于模式匹配的树的内部感兴趣,则它们由
patvarTransformer
中定义的patvarTransformer
创建 .另一方面,如果你正在使用
UnApply
树(这是在攻击后生成的),我有一个坏消息:quasiquotes目前不支持它们 . 按照SI-7789进行修复后会收到通知 .Den Shabalin指出,在这个特定的环境中不能使用quasiquotes,我设法找到一个与部分函数的案例定义模式相匹配的模式 .
关键问题是,我们要匹配的构造函数(在我们的示例中为
Data
)存储在Apply
节点的TypeTree
中 . 匹配在TypeTree
中包含的树有点棘手,因为这个类的唯一提取器(TypeTree()
)对这个特定任务没有多大帮助 . 相反,我们必须使用original
方法选择包装树:在我们的用例中,包装树是一个
Select
节点,我们现在可以检查该节点的符号是否是我们要查找的节点 .