Как оценить выражение внутри макроса Scala?

Я пытаюсь оценить 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

Если обнаружится в ML пользователя scala, эта проблема может быть решена с помощью resetAllAttrs, тем не мение

  1. Я не понимаю, как я должен это использовать.
  2. Эта функция кажется устаревшей.

Так есть ли способ решить мою проблему?


Остальная часть кода:

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 ответа

Документы для c.eval действительно скажи использовать c.resetAllAttrsОднако эта функция имеет ряд известных проблем, которые иногда приводят к непоправимому повреждению дерева, которое она обрабатывает (поэтому мы планируем удалить его в Scala 2.11 - я только что отправил запрос на извлечение, который делает это: https://github.com/scala/scala/pull/3485).

Вместо этого вы можете попробовать c.resetLocalAttrs, который имеет меньший потенциал для повреждения дерева. К сожалению, это все еще немного сломано. Мы планируем это исправить ( https://groups.google.com/forum/), однако в Scala 2.10.x и 2.11.0 не будет никакого способа сделать c.eval работать надежно.

Ну, я понял, что они имели в виду, используя 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,

Другие вопросы по тегам