Подтвердить что ты не робот

Почему среда выполнения во вселенной и вселенная макроса создают два разных дерева для scala.None?

Если у меня есть макрос, который имеет код tranforms, например:

  (src: a.b.c.TestEntity) =>
    {
      z.y.TestTable(None)
    }

Чтобы соответствовать ни одной части этого AST, я могу использовать экстрактор, например:

  object NoneExtractor {
    def unapply(t: Tree): Boolean = t match {
      case Select(Ident(scala), none) if scala.encoded == "scala" && none.encoded == "None" => true
      case _ => false
    }
  }

В качестве showRaw части "Нет" АСТ выглядит следующим образом:

Select(Ident(scala), None)

Но если я хочу написать unit test NoneExtractor, я не хочу компилировать и перестраивать макросы и размещать тест в проекте, который компилирует макрос. Я хочу unit test экстрактор в проекте макроса, который предполагает, что отражение во время выполнения - это путь:

val t = reify {

  (src: a.b.c.TestEntity) =>
    {
      z.y.TestTable(None)
    }

}.tree 

Но дерево совершенно другое, а в showRaw этого дерева None выглядит так:

Ident(scala.None)

Это плохая новость для написания отрицательных тестов и проверки обработки ошибок моего макроса. Вы не можете писать отрицательные тесты для макроса, используя макрос из другого проекта, поскольку код не будет компилироваться (и вы не можете отлаживать свой отрицательный тест с ошибками компиляции).

Почему представления о чем-то столь же фундаментальном, как None, настолько различаются между отражением времени компиляции и отражением времени выполнения? Есть ли способ создать тестируемые фрагменты дерева в макропроекте, который является тем же самым AST, который будет передан макросу во время отражения времени компиляции?

4b9b3361

Ответ 1

Чтобы обойти эту несогласованность, вы можете использовать предстоящие quasiqoutes в вашем шаблоне. Они абстрагируют АСТ и, таким образом, будут работать с обоими представлениями (AST все равно является компилятором, Scala - единственный язык компилятора, но не так хорошо полагаться на внутреннее представление компилятора):

case q"_root_.scala.None" => ...

будет соответствовать обе АСТ. Также вы можете создать дерево с q"_root_.scala.None", чтобы вам не пришлось беспокоиться о представлении. Reify будет устаревшим, когда квазикварталы будут выпущены с Scala 2.11. Чтобы использовать квазиквартины с Scala 2.10, вы можете использовать райский мир.

Вот хороший путеводитель WIP по Scala quasiquotes.