2014-02-05 3 views
2

Я пытаюсь оценить в Expr внутри макроса с помощью Context#eval метода:Как оценить выражение внутри макроса Scala?

//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.

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


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

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 

} 
+0

Было бы полезно, если бы вы могли опубликовать весь код в проекте github. Затем я убеждаюсь, что мы не пропустим ваш случай использования при установке resetAttrs. –

ответ

0

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

+0

У меня есть более страшная ошибка: 'объект Ary не является членом пакета ArrayOps', который является истинным, потому что' Ary' - это не объект, а неявный класс, как показано выше. – paradigmatic

+0

@paradigmatic В какой строке вы его набираете? Вы уверены, что это макро/контекстная ошибка? Я знаю, что макросы не всегда хорошо сочетаются с имплицитами, хотя я не уверен, в какой степени. – KChaloux

+0

Я добавил основной метод и ошибку здесь: https://gist.github.com/paradigmatic/8827878 Спасибо – paradigmatic

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 надежной.