Tôi muốn tạo một plugin tạo khuôn mẫu và khi bước đầu tiên chuyển đổi một chuỗi tùy ý thành biểu diễn AST "được biên dịch" (như trình thông dịch scala, tôi đoán). Vì vậy, một plugin trình biên dịch có thể ví dụ như gán someString để "HELLO WORLD":Biên dịch chuỗi thành AST bên trong CompilerPlugin?
@StringAnnotation("""("hello world").toString.toUpperCase""")
var someString = ""
hiện đầu tiên Plugin bắn của tôi làm trong ngắn hạn:
- runafter phân tích cú pháp
- tạo ra một đại diện mới chỉ biên dịch và một VirtualFile với nội dung chú thích
- đơn vị biên dịch và in.body
xem: http://paste.pocoo.org/show/326025/
a) Ngay bây giờ, "object o{val x = 0}"
trả về AST, nhưng ví dụ: "var x = 1+ 2"
không phải vì nó không phải là tệp .scala hợp lệ. Làm thế nào tôi có thể sửa lỗi này?
b) Chỉ có trình bày một lựa chọn tốt? Thay vào đó tôi có nên ghi đè lên computeInternalPhases với các giai đoạn thích hợp hoặc sử dụng -Ystop: phase?
c) Có thể liên kết môi trường của trình biên dịch bên ngoài với trình biên dịch bên trong hay không, ví dụ:
var x = _
(...)
@StringAnnotation("x += 3")
sẽ hoạt động?
tôi thấy mã sau [1] sử dụng một thông dịch viên và một biến mà làm điều gì đó tương tự:
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)");
nhờ
Hoàn thành 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 [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))
}
}
}