【问题标题】:def macro inside case statement案例语句中的 def 宏
【发布时间】:2015-06-27 09:40:08
【问题描述】:

我想问一下def宏在哪里可以调用,什么时候展开?我想我们不能把一个合适的生成的 AST 放在合适的地方吗? 例如,我想要这个:

(2,1) match { 
    case StandaloneMacros.permutations(1,2) => true ; 
    case (_,_) => false 
}

宏展开后变成这个

(2,1) match { 
    case (1,2) | (2,1) => true ; 
    case (_,_) => false 
}

我的宏 permutations 产生元组的替代。但是当我运行第一个 sn-p 时,我得到了

macro method permutations is not a case class, nor does it have an unapply/unapplySeq member

我也尝试使用 unapply 宏方法定义一个 Permutations 对象,但又遇到了另一个错误:

scala.reflect.internal.FatalError: unexpected tree: class scala.reflect.internal.Trees$Alternative

那么:有可能实现吗?

【问题讨论】:

标签: scala macros


【解决方案1】:

我前段时间想出了一个解决方案,我想我会与您分享。 为了完成上述任务,我使用了 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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多