Scala宏:将部分函数重写为匹配

Scala宏:将部分函数重写为匹配,scala,scala-macros,Scala,Scala Macros,我想将部分函数重写为匹配表达式 //macro and impl def pfRewrite(pf: PartialFunction[Int, Int]) = macro ResponderImpl.pfRewriteImpl def pfRewriteImpl(c: Context)(pf: c.Expr[PartialFunction[Int, Int]]) = { import c.universe._ val cas = pf.tree.collect { case

我想将
部分函数
重写为
匹配
表达式

//macro and impl
def pfRewrite(pf: PartialFunction[Int, Int]) = macro ResponderImpl.pfRewriteImpl

def pfRewriteImpl(c: Context)(pf: c.Expr[PartialFunction[Int, Int]]) = {
  import c.universe._

  val cas = pf.tree.collect {
    case x: DefDef if x.name.decoded == "applyOrElse" =>
      x.collect {
        case cq"$x => $y" =>  cq"""$x => $y"""
      }
  }.flatten

  val sVal = newTermName("someVal")

  val rewrite = q"""
    $sVal match {
      case ..$cas
    }
  """
  c.Expr(rewrite)
}
在代码中,我得到了一个
PartialFunction
并从
applyOrElse
方法中获取了一个
cases
,接下来我为“someVal”创建了一个
match
表达式。此值来自代码:

 //test
 def test {
  val someVal = 10

  pfRewrite {
   case 1 => 10
   case _ => 100
  }
 }
但我有错误:

[error]  found   : Int(10)
[error]  required: Nothing
[error]       case 1 => 10
[error]                 ^
等等


是否可以将部分函数调用重写为匹配

通常,这些令人尴尬的错误消息源于混合类型化树和非类型化树(有关更多详细信息,请参阅)。因此,在我们解决这个问题之前,最好在您计划与非类型树混合的类型树上执行resetLocalAttr

这种情况也不例外。使用
c.resetLocalAttrs(pf.tree)
而不仅仅是
pf.tree
揭示了宏扩展的真正问题:

12:57 ~/Projects/Master/sandbox (master)$ scalac Test.scala
Test.scala:5: error: not found: value default
     Macros.pfRewrite {
                      ^
如果我们启用
-Xprint:typer
,这是查看宏扩展的方式之一(以及
-Ymacro-debug-lite
-Ymacro-debug-verbose
),那么我们将看到发生了什么:

[[syntax trees at end of                     typer]] // Test.scala
package <empty> {
  object Test extends AnyRef with App {
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    };
    def test: Unit = {
      val someVal: Int = 10;
      {
        someVal match {
          case 1 => 10
          case _ => 100
          case (defaultCase$ @ _) => <default: error>.apply(<x1: error>)
        };
        ()
      }
    }
  }
}
[[typer末尾的语法树]]///Test.scala
包装{
对象测试通过应用扩展AnyRef{
def():Test.type={
测试。超级。();
()
};
def测试:单位={
val-someVal:Int=10;
{
某些比赛{
案例1=>10
案例=100
案例(defaultCase$@)=>。应用()
};
()
}
}
}
}

看起来部分函数合成还添加了一个默认情况,我们不能按原样重用,因为它引用了在合成类中定义的一些合成变量。

您能说明您期望的输出树是哪一个吗?它将用于运行时,并将
someVal
用作方法参数:
def mth(s:Int)={pfRewrite{case 1=>10;case{=>100}
转换为
mth(s:Int)={s匹配{…}
。或者你是什么意思?pfRewrite怎么知道它需要匹配s?还有,你试过在重写时调用resetLocalAttrs吗?@EugeneBurmako不,我没有使用
resetLocalAttrs
s
是一个属性名。现在,我想重写
case
块-
case x:Int=>x
转换为
case x:Int=>x+100
。可能还是很难?