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

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

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

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

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

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

4b9b3361

Ответ 1

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

Mirko Stocker, написал свой Мастер-тезис о Scala Рефакторинг, В Приложении D (стр. 95) он описывает архитектуру АСТ. Он также включает графический обзор:

Scala AST

Еще один способ найти информацию об АСТ - это прямо посмотреть в источники reflect.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(())))

Ответ 2

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

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

Преимущество такого подхода над showRaw заключается в том, что он не требует кода для typecheck. Вы можете написать небольшой фрагмент кода, который ссылается на несуществующие переменные или классы, и он все равно успешно выполнит и покажет вам 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))))))))

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