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
}