2011-01-26 7 views
6

Vorrei creare un plug-in per i template e come primo passo convertire una stringa arbitraria nella sua rappresentazione AST "compilata" (come immagina l'interprete scala). Quindi, un plugin compilatore potrebbe ad esempio assegnare someString a "CIAO MONDO":Compilare la stringa a AST all'interno di CompilerPlugin?

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

Il mio attuale primo plugin colpo fa in breve:

  • runafter parser
  • creare una nuova rappresentazione solo compilatore e un VirtualFile con il contenuto delle annotazioni
  • compilazione e stampa unit.body

vedi: 0.123.

a) Al momento, "object o{val x = 0}" restituisce un AST, ma ad es. "var x = 1+ 2" non perché non sarebbe un file .scala valido. Come posso risolvere questo?

b) Rappresenta solo una buona scelta? Dovrei invece ignorare computeInternalPhases con le fasi appropriate o usare -Ystop: phase?

c) È possibile associare l'ambiente del compilatore esterno a quello interno, in modo che ad es.

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

funzionerebbe?

ho trovato il codice seguente [1] con un interprete e una variabile che fa qualcosa di simile:

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

grazie

codice completo:

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 <code>preTransform</code>, each node is 
     * visited before its children. 
     */ 
     def preTransform(tree: Tree): Tree = tree match { 
     case [email protected](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)) 
     } 
    } 
    } 

risposta

1

Non so se questo ti aiuta molto, ma invece di giocherellare con l'interprete, è possibile utilizzare treeFrom (aString) che fa parte del progetto scala-refactoring (http://scala-refactoring.org/). non risponde alla tua domanda sui cross-binding, però ...