Compile String to AST inside CompilerPlugin?

I would like to create a templating plugin and, as a first step, convert an arbitrary string into this โ€œcompiledโ€ AST representation (it seems to me to be a scala interpreter). Thus, a compiler plugin could, for example, assign someString "HELLO WORLD":

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

My current plugin with the first shot in a nutshell:

  • parser to parse
  • create only a new view compiler and VirtualFile with annotation content
  • compile and print unit.body

see http://paste.pocoo.org/show/326025/

a) Right now, "object o{val x = 0}" returns an AST, but, for example, "var x = 1+ 2" not because it will not be a valid .scala file. How can i fix this?

b) Is presentation only a good choice? Should I instead override computeInternalPhases with the appropriate phases or use -Ystop: phase?

c) Is it possible to associate an external compiler environment with an internal one, so

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

will work?

I found the following code [1] using an interpreter and one variable that does something like this:

  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

thanks

The code:

 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 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
compiler-construction scala
source share
1 answer

I donโ€™t know if this will help you much, but instead of messing with the interpreter, you can use treeFrom (aString), which is part of the scala -refactoring project ( http://scala-refactoring.org/ ). doesn't answer your cross-linking question though ...

+1
source share

All Articles