case 语句中的 def 宏
def macro inside case statement
请问def宏在哪里可以调用,什么时候展开?我想我们不能把一个合适的生成的 AST 放在它合适的任何地方?
例如,我想要这个:
(2,1) match {
case StandaloneMacros.permutations(1,2) => true ;
case (_,_) => false
}
宏展开后变成这样
(2,1) match {
case (1,2) | (2,1) => true ;
case (_,_) => false
}
我的宏 排列 生成元组的替代项。但是当我 运行 第一个片段时,我得到
macro method permutations is not a case class, nor does it have an unapply/unapplySeq member
我也尝试用 unapply macro 方法定义一个 Permutations 对象,但出现另一个错误:
scala.reflect.internal.FatalError: unexpected tree: class scala.reflect.internal.Trees$Alternative
所以:有可能实现吗?
前段时间我想到了一个解决方案,我想我会和你分享。
为了完成上述任务,我使用了 Transformer 和 transformCaseDefs
object Matcher {
def apply[A, B](expr: A)(patterns: PartialFunction[A, B]): B = macro apply_impl[A,B]
def apply_impl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context)(expr: c.Expr[A])(patterns: c.Expr[PartialFunction[A, B]]): c.Expr[B] = {
import c.universe._
def allElemsAreLiterals(l: List[Tree]) = l forall {
case Literal(_) | Ident(_) => true
case _ => throw new Exception("this type of pattern is not supported")
}
val transformer = new Transformer {
override def transformCaseDefs(trees: List[CaseDef]) = trees.map {
case cas @ CaseDef(pat @ Apply(typTree, argList), guard, body) if allElemsAreLiterals(argList) =>
val permutations = argList.permutations.toList.map(t => q"(..$t)").map {
case Apply(_, args) => Apply(typTree, args)
}
val newPattern = Alternative(permutations)
CaseDef(newPattern, guard, body)
case x => x
}
}
c.Expr[B](q"${transformer.transform(patterns.tree)}($expr)")
}
}
它会更短,但是您需要以某种方式提供与原始(转换前)case 语句中使用的相同的 TypeTree。
这样,就可以这么用了
val x = (1,2,3)
Matcher(x) {
case (2,3,1) => true
case _ => false
}
然后翻译成
val x = (1,2,3)
x match {
case (1,2,3) | (1,3,2) | (2,1,3) | (2,3,1) | (3,1,2) | (3,2,1) => true
case _ => false
}
请问def宏在哪里可以调用,什么时候展开?我想我们不能把一个合适的生成的 AST 放在它合适的任何地方? 例如,我想要这个:
(2,1) match {
case StandaloneMacros.permutations(1,2) => true ;
case (_,_) => false
}
宏展开后变成这样
(2,1) match {
case (1,2) | (2,1) => true ;
case (_,_) => false
}
我的宏 排列 生成元组的替代项。但是当我 运行 第一个片段时,我得到
macro method permutations is not a case class, nor does it have an unapply/unapplySeq member
我也尝试用 unapply macro 方法定义一个 Permutations 对象,但出现另一个错误:
scala.reflect.internal.FatalError: unexpected tree: class scala.reflect.internal.Trees$Alternative
所以:有可能实现吗?
前段时间我想到了一个解决方案,我想我会和你分享。 为了完成上述任务,我使用了 Transformer 和 transformCaseDefs
object Matcher {
def apply[A, B](expr: A)(patterns: PartialFunction[A, B]): B = macro apply_impl[A,B]
def apply_impl[A: c.WeakTypeTag, B: c.WeakTypeTag](c: Context)(expr: c.Expr[A])(patterns: c.Expr[PartialFunction[A, B]]): c.Expr[B] = {
import c.universe._
def allElemsAreLiterals(l: List[Tree]) = l forall {
case Literal(_) | Ident(_) => true
case _ => throw new Exception("this type of pattern is not supported")
}
val transformer = new Transformer {
override def transformCaseDefs(trees: List[CaseDef]) = trees.map {
case cas @ CaseDef(pat @ Apply(typTree, argList), guard, body) if allElemsAreLiterals(argList) =>
val permutations = argList.permutations.toList.map(t => q"(..$t)").map {
case Apply(_, args) => Apply(typTree, args)
}
val newPattern = Alternative(permutations)
CaseDef(newPattern, guard, body)
case x => x
}
}
c.Expr[B](q"${transformer.transform(patterns.tree)}($expr)")
}
}
它会更短,但是您需要以某种方式提供与原始(转换前)case 语句中使用的相同的 TypeTree。
这样,就可以这么用了
val x = (1,2,3)
Matcher(x) {
case (2,3,1) => true
case _ => false
}
然后翻译成
val x = (1,2,3)
x match {
case (1,2,3) | (1,3,2) | (2,1,3) | (2,3,1) | (3,1,2) | (3,2,1) => true
case _ => false
}