私は Scala 組み込み DSL で作業しており、マクロは私の目的を達成するための主要なツールになりつつあります。入力マクロ式のサブツリーを結果のマクロ式に再利用しようとすると、エラーが発生します。状況は非常に複雑ですが、(願わくば) 理解できるように単純化しました。
次のコードがあるとします。
val y = transform {
val x = 3
x
}
println(y) // prints 3
ここで、'transform' は関連するマクロです。まったく何もしないように見えるかもしれませんが、実際には、表示されているブロックを次の式に変換しています。
3 match { case x => x }
これは、次のマクロ実装で行われます。
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
}
}
xNamは変数名に対応し、xValは関連する値に対応し、最後にxExpは変数を含む式に対応することに注意してください。xExp の raw ツリーを出力すると、Ident(newTermName("x"))が得られます。これは、RHS の場合に設定されているものとまったく同じです。式は変更される可能性があるため (x の代わりに x+2 など)、これは有効な解決策ではありません。私がやりたいことは、「x」の意味を変更しながら xExp ツリー (xExp コメントを参照) を再利用することです (これは入力式の定義ですが、出力式ではケース LHS 変数になります)。以下に要約された長いエラー:
symbol value x does not exist in org.habla.main.Main$delayedInit$body.apply); see the error output for details.
私の現在の解決策は、xExp を解析してすべての Ident を新しいものに置き換えることですが、これはコンパイラの内部構造に完全に依存しているため、一時的な回避策です。xExp には、showRaw が提供するよりも多くの情報が含まれていることは明らかです。「x」がケース変数の役割を果たせるようにするために、そのxExpをきれいにするにはどうすればよいですか? このエラーの全体像を説明できる人はいますか?
PS:私はTreeApiの代替* メソッド ファミリを使用しようとして失敗しましたが、その意味を理解するための基本が欠けています。