Estoy trabajando en un DSL incorporado Scala y las macros se están convirtiendo en una herramienta principal para lograr mis propósitos. Obtengo un error al intentar reutilizar un subárbol de la expresión de macro entrante en el resultante. La situación es bastante compleja, pero (espero) la he simplificado para su comprensión.¿Cómo puedo reutilizar los subárboles de definición (AST) en una macro?
Supongamos que tenemos este código:
val y = transform {
val x = 3
x
}
println(y) // prints 3
donde 'transformar' es la macro involucrados. Aunque podría parecer que no hace absolutamente nada, en realidad está transformando el bloque mostrado en esta expresión:
3 match { case x => x }
Se realiza con esta macro aplicación:
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
}
}
en cuenta que xNam se corresponde con el nombre de variable, xVal corresponde con su valor asociado y finalmente xExp se corresponde con la expresión que contiene la variable. Bueno, si imprimo el árbol sin procesar xExp obtengo Ident (newTermName ("x")), y eso es exactamente lo que se establece en el caso RHS. Dado que la expresión se puede modificar (por ejemplo, x + 2 en lugar de x), esta no es una solución válida para mí. Lo que quiero hacer es reutilizar el árbol xExp (ver el comentario xExp) mientras altera el significado 'x' (es una definición en la expresión de entrada pero será una variable LHS de caso en la salida), pero lanza un de error a largo resume en:
symbol value x does not exist in org.habla.main.Main$delayedInit$body.apply); see the error output for details.
Mi solución actual consiste en el análisis de la xExp a sustitute todos los Idents por otras nuevas, pero es totalmente dependiente de las partes internas del compilador, y por lo tanto, una solución temporal. Es obvio que el xExp viene con más información que el ofrecido por showRaw. ¿Cómo puedo limpiar ese xExp para permitir que 'x' emita la variable de caso? ¿Alguien puede explicar la imagen completa de este error?
PD: he intentado sin éxito utilizar la familia de métodos sustituto * del TreeApi, pero me faltan elementos básicos para comprender sus implicaciones.
¿Ha funcionado 'resetAllAttrs', después de todo? –
Sí, lo hizo. Funcionó en el código mostrado, así como en un árbol bastante complejo con varios "cambios" variables. – jeslg
Has llamado 'resetAllAttrs' en el resultado' c.Expr', en 'block', o en algún árbol seleccionado? –