Sto provando a scrivere un plug-in del compilatore Scala che consentirà la generazione di codice estremamente generica: qualcosa come la generalità del preprocessore C, ma un po 'più typesafe (non sono sicuro se questo è un'idea terribile, ma è un esercizio divertente). Il mio caso d'uso ideale simile a questa:Chiusura del passaggio al plugin del compilatore Scala
// User code. This represents some function that might take some args
// and outputs an abstract syntax tree.
def createFooTree(...): scala.reflect.runtime.universe.Tree = ...
// Later user code (maybe separate compilation?). Here the user generates
// code programmatically using the function call to |createFooTree| and inserts
// the code using insertTree.
insertTree(createFooTree(...))
Il codice del plugin importante potrebbe assomigliare a questo (sulla base di this):
class InsertTreeComponent(val global: Global)
extends PluginComponent
with TypingTransformers {
import global._
import definitions._
override val phaseName = "insertTree"
override val runsRightAfter = Some("parser")
override val runsAfter = runsRightAfter.toList
override val runsBefore = List[String]("typer")
def newPhase(prev: Phase): StdPhase = new StdPhase(prev) {
def apply(unit: CompilationUnit) {
val onTransformer = new TypingTransformer(unit) {
override def transform(tree: Tree): Tree = tree match {
case orig @ Apply(
function,
// |treeClosure| is the closure we passed, which should
// evaluate to a Tree (albeit a runtime Tree).
// The function.toString bit matches anything that looks like a
// function call with a function called |insertTree|.
treeClosure) if (function.toString == "insertTree") => {
// This function evaluates and returns the Tree, inserting it
// into the call site as automatically-generated code.
// Unfortunately, the following line isn't valid.
eval(treeClosure): Tree
}
...
Qualsiasi idea di come fare questo? Per favore non dire "usa solo macro"; almeno in 2.10, non sono abbastanza generali.
BTW, vedo due problemi con l'approccio che ho delineato: 1) Il plug-in del compilatore accetta un AST, non una chiusura. Avrebbe bisogno di un modo per creare la chiusura, probabilmente aggiungendo una dipendenza di compilazione sul codice utente. 2) L'utente non ha accesso a scala.reflect.internal.Trees.Tree, solo scala.reflect.runtime.universe.Tree, quindi il plugin dovrebbe tradurre tra i due.
È decisamente una pessima idea - ma un grande esercizio;) - devi pensare di guardare a fare macro impl di macro in paradiso. –