Где я могу узнать о создании AST для макросов Scala?

Где я могу научиться создавать AST, которые генерируют макросы Scala?

Скаладок не так полезен, как хотелось бы. Например:

abstract def Apply(sym: Universe.Symbol, args: Universe.Tree*): Universe.Tree
A factory method for Apply nodes.

Но как мне узнать, что такое узел Apply? Где я могу найти список типов узлов в AST и как они сочетаются друг с другом?

2 ответа

Решение

Существует не так много документации по внутренним компонентам компилятора, но доступных вещей должно быть достаточно для начала работы.

Mirko Stocker написал магистерскую диссертацию о рефакторинге Scala. В Приложении D (стр. 95) он описывает архитектуру AST. Он также включает в себя графический обзор:

Скала АСТ

Еще один способ найти информацию об AST - это посмотреть непосредственно на источники refle.internal.Trees, которые содержат AST.

Если нужно выяснить, как конкретный фрагмент исходного кода представлен внутри, есть reify:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> showRaw(reify{val i = 0}.tree)
res8: String = Block(List(ValDef(Modifiers(), newTermName("i"), TypeTree(),
  Literal(Constant(0)))), Literal(Constant(())))

Вы можете взглянуть на скаладок ( http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html) или на слайды ( http://scalamacros.org/talks/2012-04-28-MetaprogrammingInScala210.pdf, часть "Учимся учиться").

Вот что я обычно делаю. Я написал простой скрипт parse, который принимает в качестве аргумента код Scala, а затем компилирует его -Xprint:parser -Ystop-after:parser -Yshow-trees-stringified -Yshow-trees-compact (parse использует другой вспомогательный скрипт: adhoc-scalac, нажмите здесь, чтобы увидеть его источники).

Преимущество этого подхода перед showRaw является то, что он не требует кода для проверки типов. Вы можете написать небольшой фрагмент кода, который ссылается на несуществующие переменные или классы, и он все равно будет успешно запущен и покажет вам AST. Вот пример вывода:

09:26 ~$ parse 'class C { def x = 2 }'
[[syntax trees at end of parser]]// Scala source: tmp36sVGp
package <empty> {
  class C extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    def x = 2
  }
}
PackageDef(Ident(TermName("<empty>")), List(ClassDef(Modifiers(), TypeName("C"), List(), Template(List(Select(Ident(scala), TypeName("AnyRef"))), emptyValDef, List(DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))), DefDef(Modifiers(), TermName("x"), List(), List(), TypeTree(), Literal(Constant(2))))))))

Там также есть скрипт typecheck, который делает то же самое, но останавливается после typer, Иногда полезно понять, как именно средство проверки типов преобразует деревья синтаксического анализатора. Однако и наборы инструментов, и макросы работают с деревьями синтаксического анализатора, поэтому я использую typecheck для строительства деревьев очень редко.

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