2011-01-26 8 views
6

私はテンプレートプラグインを作成したいと思います。最初のステップとして任意の文字列を "コンパイル済み" AST表現に変換します(scalaインタプリタのように)。だから、コンパイラプラグインは、例えば「HELLO WORLD」にsomeStringを割り当てることができます:CompilerPlugin内のASTとの文字列をコンパイルしますか?

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

私の現在の第1ショットプラグインが短い中で行います。

  • runafterパーサ
  • 新しい表現のみコンパイラとVirtualFileを作成します注釈内容と
  • コンパイルおよび印刷unit.body

を参照してください:現在、"object o{val x = 0}"はASTを返します。たとえば、ASTを返します。たとえば、"object o{val x = 0}"は、ASTを返します。たとえば、ASTを返します。たとえば、"object o{val x = 0}"は、ASTを返します。 "var x = 1+ 2"は有効な.scalaファイルではないため、表示されません。これをどうすれば解決できますか?

b) 唯一のプレゼンテーションはいいですか?代わりに適切なフェーズで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 <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)) 
     } 
    } 
    } 

答えて

1

これがあなたには大いに役立つかどうかわかりませんが、fiddlの代わりにInterpreterを使用すると、スカラリファクタリングプロジェクト(http://scala-refactoring.org/)の一部であるtreeFrom(aString)を使用できます。しかし、クロスバインディングに関する質問には答えません。