2016-07-01 3 views
3

Это упрощенная версия проблемы, с которой я столкнулся, но основная проблема остается. После вызова макроса я хочу динамически генерировать классы case. Я могу получить параметры из вызова макросов и т. Д. У меня возникает проблема с использованием строковой переменной в квазикварталах. Я по существу хочу иметь следующее:Подъемная строковая переменная с использованием квазиквартальных значений Scala

def expand_impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { 
    import c.universe._ 

    val toGen = "case class Foo()" 

    val toReturn = c.Expr[Any](
     q"$toGen" 
    ) 
    toReturn 
} 

Однако класс case не сгенерирован. Теперь я знаю, что если я изменю toGen на q "case class Foo()", он будет работать, однако toGen - это строка, которую я буду генерировать после некоторой другой обработки, которая возвращает строку, поэтому я не могу этого сделать. компилировать его, как это и вручную, глядя на стоимости toReturn я получаю следующее:

Expr[Any]("case class Foo()") 

Строка toGen просто вставляется в, а также цитаты, то есть класс случае не генерируется.

Я искал похожие проблемы, но не могу найти этот пример в любом месте. Как я могу исключить двойные кавычки строковой переменной в квазикварталах?

+0

Если вы хотите использовать квазивоты, вы должны использовать их для каждого вложенного выражения, иначе вы просто поднимете строковые выражения. Почему при построении объявления класса case нельзя использовать квазивоты? – devkat

+0

Идея состоит в следующем: 'val toGen = someMethod()'. Строка, возвращаемая 'someMethod()', будет чем-то вроде «case class Foo()». Если вы правильно поняли, вы предлагаете мне использовать квазивоты при возврате класса case? Однако именно здесь моя проблема заключается в том, что 'someMethod()' не всегда возвращает один и тот же класс case, он динамически генерирует их на основе ввода и т. Д. И возвращает строку. – brioche

+0

Проблема заключается в том, что квазиквасоты не анализируют строки, поэтому всякий раз, когда выражение, которое вы хотите поднять, выражается в виде строки, вы не можете их использовать. В этом случае вам нужно разобрать строку, как показывает Режис Жан-Жиль в своем ответе. – devkat

ответ

3

Существует метод parse, определенный на Context. Он возвращает Tree, и поскольку деревья могут быть интерполированы в квазикварталах, вы можете легко смешивать и сопоставлять парсинг с квазикотанием. К примеру:

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

import scala.reflect.macros.whitebox.Context 
import scala.language.experimental.macros 

def test_impl(c: Context)(): c.Tree = { 
    import c.universe._ 
    val tree = c.parse("""println(2)""") 
    q"println(1); $tree; println(3)" 
} 
def test(): Unit = macro test_impl 

// Exiting paste mode, now interpreting. 

import scala.reflect.macros.whitebox.Context 
import scala.language.experimental.macros 
test_impl: (c: scala.reflect.macros.whitebox.Context)()c.Tree 
defined term macro test:()Unit 

scala> test() 
1 
2 
3 

В этом примере я определил макрос четкости, но он должен работать так же хорошо, с макро-аннотации (как в вашем случае).

+0

Работает как шарм, большое спасибо! – brioche

Смежные вопросы