Как добавить новый класс в плагин компилятора Scala? - PullRequest
36 голосов
/ 17 октября 2011

В плагине компилятора Scala я пытаюсь создать новый класс, который реализует ранее существовавшую черту. Пока мой код выглядит так:

def trait2Impl(original: ClassDef, newName: String): ClassDef = {
    val impl = original.impl
    // Seems OK to have same self, but does not make sense to me ...
    val self = impl.self
    // TODO: implement methods ...
    val body = impl.body
    // We implement original
    val parents = original :: impl.parents
    val newImpl = treeCopy.Template(impl, parents, self, body)
    val name = newTypeName(newName)
    // We are a syntheic class, not a user-defined trait
    val mods = (original.mods | SYNTHETIC) &~ TRAIT
    val tp = original.tparams
    val result = treeCopy.ClassDef(original, mods, name, tp, newImpl)
    // Same Package?
    val owner = original.symbol.owner
    // New symbol. What's a Position good for?
    val symbol = new TypeSymbol(owner, NoPosition, name)
    result.setSymbol(symbol)
    symbol.setFlag(SYNTHETIC)
    symbol.setFlag(ABSTRACT)
    symbol.resetFlag(INTERFACE)
    symbol.resetFlag(TRAIT)
    owner.info.decls.enter(symbol)
    result
}

Но, похоже, он не добавлен в пакет. Я подозреваю, что это потому, что на самом деле пакет был «пройден» до признака, который вызывает генерацию, и / или потому что метод «override def transform (tree: Tree): Tree» в TypingTransformer может вернуть только one Дерево, для каждого дерева, которое оно получает, поэтому оно не может создать новое дерево, а только изменить его.

Итак, как вы добавляете новый класс в существующий пакет? Возможно, это сработает, если я преобразую пакет, когда его получит «transform (Tree)», но я пока не знаю, что такое содержимое пакета, поэтому я не могу сгенерировать новый класс так рано (или я мог?) , Или, может быть, это связано с параметром «Положение» символа?

До сих пор я нашел несколько примеров, где деревья модифицируются, но ни одного, где совершенно новый класс создается в плагине компилятора.

1 Ответ

3 голосов
/ 11 февраля 2012

Полный исходный код здесь: https://gist.github.com/1794246

Хитрость заключается в том, чтобы сохранить вновь созданные ClassDef s и использовать их при создании нового PackageDef.Обратите внимание, что вам нужно иметь дело как с символами, так и с деревьями: символ пакета - это просто ручка.Чтобы сгенерировать код, вам нужно сгенерировать AST (как и для класса, где символ содержит имя и тип класса, но код находится в деревьях ClassDef).

Как вы заметилиопределения пакетов выше по дереву, чем классы, поэтому вам нужно сначала выполнить повторение (при условии, что вы создадите новый класс из существующего класса).Затем, после обхода поддеревьев, вы можете подготовить новый PackageDef (у каждого модуля компиляции есть определение пакета, которое по умолчанию является пустым пакетом) с новыми классами.

В примере, если исходный код равен

class Foo {
  def foo {
    "spring"
  }
}

, компилятор преобразует его в

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
}

, а плагин преобразует его в

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
  package mypackage {
    class MyClass extends AnyRef
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...