Wie kann ich AST-Teilbäume (Definition) in einem Makro wiederverwenden?

Ich arbeite in einem Scala Embedded DSL und Makros werden zu einem Hauptwerkzeug, um meine Ziele zu erreichen. Beim Versuch, einen Teilbaum aus dem eingehenden Makroausdruck in den resultierenden wiederzuverwenden, tritt ein Fehler auf. Die Situation ist ziemlich komplex, aber (ich hoffe) ich habe es für das Verständnis vereinfacht.

Angenommen, wir haben diesen Code:

val y = transform {
  val x = 3
  x
}
println(y) // prints 3

Dabei ist 'transform' das beteiligte Makro. Obwohl es den Anschein hat, dass es absolut nichts tut, verwandelt es den gezeigten Block tatsächlich in diesen Ausdruck:

3 match { case x => x }

Mit dieser Makroimplementierung ist es erledigt:

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
  }
}

Beachte dasxNam entspricht dem Variablennamen,xVal entspricht dem zugehörigen Wert und schließlichxExp entspricht dem Ausdruck, der die Variable enthält. Nun, wenn ich den xExp-Rohbaum drucke, erhalte ichIdent (newTermName ("x")), und genau das ist bei RHS eingestellt. Da der Ausdruck geändert werden kann (z. B. x + 2 anstelle von x), ist dies für mich keine gültige Lösung. Ich möchte den xExp-Baum (siehe xExp-Kommentar) wiederverwenden, während ich die 'x'-Bedeutung ändere (dies ist eine Definition im Eingabeausdruck, wird aber in der Ausgabe eine LHS-Variable für Groß- und Kleinschreibung sein), aber es startet a langer Fehler zusammengefasst in:

symbol value x does not exist in org.habla.main.Main$delayedInit$body.apply); see the error output for details.

Meine derzeitige Lösung besteht darin, das xExp zu analysieren, um alle Idents mit neuen zu ersetzen. Sie hängt jedoch vollständig von den Compiler-Interna ab und ist daher eine zeitliche Umgehung. Es ist offensichtlich, dass der xExp mit mehr Informationen einhergeht, als der von showRaw angebotene. Wie kann ich dieses xExp bereinigen, damit 'x' die case-Variable rollen kann? Kann jemand das ganze Bild dieses Fehlers erklären?

PS: Ich habe erfolglos versucht, die Ersatzmethodenfamilie * aus der zu verwendenTreeApi Mir fehlen jedoch die Grundlagen, um die Auswirkungen zu verstehen.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage