Скомпилировать строку в AST внутри CompilerPlugin?

Я хотел бы создать подключаемый модуль для создания шаблонов и в качестве первого шага преобразовать произвольную строку в ее "скомпилированное" представление AST (как, я полагаю, интерпретатор scala). Таким образом, плагин компилятора может, например, назначить someString для "HELLO WORLD":

  @StringAnnotation("""("hello world").toString.toUpperCase""")
  var someString = ""

Мой текущий плагин first shot вкратце делает:

  • runafter parser
  • создает новый компилятор только для представления и VirtualFile с содержанием аннотации
  • скомпилируйте и распечатайте unit.body

см .: http: //paste.pocoo. Прямо сейчас «объект o {val x = 0}» возвращает AST, но, например, «var x = 1+ 2» не возвращает, потому что это недопустимо. .scala файл. Как я могу это исправить?

б) OnlyPresentation - хороший выбор? Должен ли я вместо этого заменить computeInternalPhases соответствующими фазами или использовать -Ystop: phase?

c) Можно ли связать среду внешнего компилятора с внутренним, чтобы, например,

  var x = _
  (...)
  @StringAnnotation("x += 3")

работало?

Я нашел следующий код [1], использующий интерпретатор и одну переменную, которая делает что-то подобное:

  Interpreter interpreter = new Interpreter(settings);
  String[] context = { "FOO" };
  interpreter.bind("context", "Array[String]", context);
  interpreter
    .interpret("de.tutorials.scala2.Test.main(context)");
  context[0] = "BAR";
  interpreter
    .interpret("de.tutorials.scala2.Test.main(context)");

[1] http : //www.tutorials.de/java/320639-beispiel-zur-einbindung-des-scala-interpreters-kompilierte-scala-anwendungen.html#post1653884

спасибо

Полный код:

class AnnotationsPI(val global: Global) extends Plugin {
  import global._
  val name = "a_plugins::AnnotationsPI" //a_ to run before namer
  val description = "AST Trans PI"
  val components = List[PluginComponent](Component)

  private object Component extends PluginComponent with Transform with TypingTransformers with TreeDSL {
    val global: AnnotationsPI.this.global.type = AnnotationsPI.this.global
    val runsAfter = List[String]("parser");
    val phaseName = AnnotationsPI.this.name

    def newTransformer(unit: CompilationUnit) = {
      new AnnotationsTransformer(unit)
    }

    val SaTpe = "StringAnnotation".toTypeName

    class AnnotationsTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {

      /** When using preTransform, each node is
       *  visited before its children.
       */
      def preTransform(tree: Tree): Tree = tree match {
        case anno@ValDef(Modifiers(_, _, List(Apply(Select(New(Ident(SaTpe)), _), List(Literal(Constant(a))))), _), b, c, d) => //Apply(Select(New(Ident(SaTpe)), /*nme.CONSTRUCTOR*/_), /*List(x)*/x)
          val str = a.toString
          val strArr = str.getBytes("UTF-8")
          import scala.tools.nsc.{ Global, Settings, SubComponent }
          import scala.tools.nsc.reporters.{ ConsoleReporter, Reporter }

          val settings = new Settings()
          val compiler = new Global(settings, new ConsoleReporter(settings)) {
            override def onlyPresentation = true
          }

          val run = new compiler.Run
          val vfName = "Script.scala"
          var vfile = new scala.tools.nsc.io.VirtualFile(vfName)

          val os = vfile.output
          os.write(strArr, 0, str.size) // void  write(byte[] b, int off, int len) 
          os.close
          new scala.tools.nsc.util.BatchSourceFile(vfName, str)
          run.compileFiles(vfile :: Nil)
          for (unit <- run.units) {
            println("Unit: " + unit)
            println("Body:\n" + unit.body)
          }
          tree

        case _ =>
          tree
      }

      override def transform(tree: Tree): Tree = {
        super.transform(preTransform(tree))
      }
    }
  }

6
задан Stefan K. 27 January 2011 в 17:29
поделиться