Как оценить выражение внутри макроса 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
, тем не мение
- Я не понимаю, как я должен это использовать.
- Эта функция кажется устаревшей.
Так есть ли способ решить мою проблему?
Остальная часть кода:
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
,