Sto lavorando a un DSL incorporato di Scala e i macro stanno diventando uno strumento principale per raggiungere i miei scopi. Ricevo un errore durante il tentativo di riutilizzare una sottostruttura dall'espressione della macro in entrata in quella risultante. La situazione è abbastanza complessa, ma (spero) l'ho semplificata per la sua comprensione.Come posso riutilizzare i sottotitoli di definizione (AST) in una macro?
Supponiamo di avere questo codice:
val y = transform {
val x = 3
x
}
println(y) // prints 3
dove 'trasformare' è la macro coinvolti. Anche se potrebbe sembrare che non fa assolutamente nulla, è davvero trasformando il blocco mostrato in questa espressione:
3 match { case x => x }
E 'fatto con questa macro implementazione:
def transform(c: Context)(block: c.Expr[Int]): c.Expr[Int] = {
import c.universe._
import definitions._
block.tree match {
/* {
* val xNam = xVal
* xExp
* }
*/
case Block(List(ValDef(_, xNam, _, xVal)), xExp) =>
println("# " + showRaw(xExp)) // prints Ident(newTermName("x"))
c.Expr(
Match(
xVal,
List(CaseDef(
Bind(xNam, Ident(newTermName("_"))),
EmptyTree,
/* xExp */ Ident(newTermName("x"))))))
case _ =>
c.error(c.enclosingPosition, "Can't transform block to function")
block // keep original expression
}
}
noti che xNam corrisponde al nome variabile, xVal corrisponde al valore associato e infine xExp corrisponde all'espressione che contiene la variabile. Bene, se stampo l'albero crudo xExp ottengo Ident (newTermName ("x")), e questo è esattamente ciò che è impostato nel caso RHS. Poiché l'espressione potrebbe essere modificata (ad esempio x + 2 anziché x), questa non è una soluzione valida per me. Quello che voglio fare è riutilizzare l'albero xExp (vedere il commento xExp) mentre si altera il significato di 'x' (è una definizione nell'espressione di input ma sarà una variabile di caso LHS nell'output), ma avvia un lungo errore di riassumere in:
symbol value x does not exist in org.habla.main.Main$delayedInit$body.apply); see the error output for details.
mia soluzione attuale consiste nella analisi della xExp a sustitute tutte le Idents con quelli nuovi, ma è totalmente dipendente i meccanismi interni del compilatore, e così, una soluzione temporale. È ovvio che xExp sia accompagnato da ulteriori informazioni offerte da showRaw. Come posso pulire xExp per consentire a 'x' di modificare la variabile del caso? Qualcuno può spiegare l'intera immagine di questo errore?
PS: Ho cercato invano di utilizzare la famiglia di metodi sostitutivi * dallo TreeApi ma mi mancano le nozioni di base per comprenderne le implicazioni.
"resetAllAttrs" ha funzionato, dopo tutto? –
Sì, lo ha fatto. Ha funzionato nel codice mostrato, così come in un albero abbastanza complesso con diverse variabili "modifiche". – jeslg
Hai chiamato 'resetAllAttr' sul risultato' c.Expr', su 'block', o su un albero selezionato? –