如何评估Scala宏中的表达式?

时间:2014-02-05 14:37:38

标签: scala macros scala-macros scala-macro-paradise

我正在尝试使用Expr方法评估宏内的Context#eval

//Dummy implementation
def evalArrayTree(c: Context)(a: c.Expr[ArrayTree]): c.Expr[Array[Double]] = {
  import c.universe._
  println( c.eval(a) )

  val tree = reify( Array(0.0,0.0,0.0) ).tree 
  c.Expr[Array[Double]]( tree )
}

然而,编译器抱怨:

[error] /home/falcone/prg/sbt-example-paradise/core/src/main/scala/Test.scala:20: exception during macro expansion: 
[error] scala.tools.reflect.ToolBoxError: reflective toolbox has failed

如果在scala-user ML中找到,可以使用resetAllAttrs解决问题。然而

  1. 我不明白我应该如何使用它。
  2. 此功能seems to be deprecated
  3. 那么有办法解决我的问题吗?


    其余代码:

    object ArrayEval {
    
      import scala.language.experimental.macros
    
      def eval( a: ArrayOps.ArrayTree ): Array[Double] = macro Macros.evalArrayTree
    
    }
    
    object ArrayOps {
    
      sealed trait ArrayTree {
        def +( that: ArrayTree ) = Plus( this, that )
      }
    
      implicit class Ary( val ary: Array[Double] ) extends ArrayTree
      case class Plus( left: ArrayTree, right: ArrayTree ) extends ArrayTree
    
    }
    

2 个答案:

答案 0 :(得分:3)

c.eval的文档确实告诉使用c.resetAllAttrs,但是这个函数有许多已知的问题,有时会使它无法修复它所处理的树(这就是我们计划删除的原因)它在Scala 2.11中 - 我刚刚提交了一个拉取请求:https://github.com/scala/scala/pull/3485)。

您可以尝试的是c.resetLocalAttrs,它具有较小的树腐败可能性。不幸的是,它仍然有点破碎。我们计划修复它(https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ),但是在Scala 2.10.x和2.11.0中,将无法使c.eval可靠地工作。

答案 1 :(得分:1)

好吧,我通过resetAllAttrs找出了他们的意思。我的示例已针对Int输入进行了简化,但我能够通过执行以下操作来复制并修复您描述的错误:

import scala.language.experimental.macros
import scala.reflect.runtime.universe._
import scala.reflect.macros.BlackboxContext

def _evalMacro(c: BlackboxContext)(a: c.Expr[Int]) = {
  import c.universe._

  val treeReset = c.resetAllAttrs(a.tree) // Reset the symbols in the tree for 'a'
  val newExpr = c.Expr(treeReset)         // Construct a new expression for the updated tree

  println(c.eval(newExpr)) // Perform evaluation on the newly constructed expression
  ...                      // Do what you do
}

def evalMacro(a: Int) = macro _evalMacro

我打算猜测你使用resetAllAttrs是好的,至少在Scala的某些未来版本问世之前。 2.11甚至没有给出使用的弃用警告。

注意:我正在使用Scala 2.11。我相信这在2.10中应该相同,除非您使用Context代替BlackboxContext