Как я могу повторно использовать поддеревья определения (AST) в макросе?

Я работаю во встроенном DSL Scala, и макросы становятся основным инструментом для достижения моих целей. Я получаю сообщение об ошибке при попытке повторно использовать поддерево из входящего выражения макроса в полученное. Ситуация довольно сложная, но (я надеюсь) я упростил ее для ее понимания.

Предположим, у нас есть этот код:

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

где «трансформировать» это задействованный макрос. Хотя может показаться, что он абсолютно ничего не делает, он действительно преобразовывает показанный блок в это выражение:

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, я получаюIdent(newTermName("x"))и это именно то, что установлено в случае RHS. Поскольку выражение может быть изменено (например, x + 2 вместо x), это не является правильным решением для меня. То, что я хочу сделать, это повторно использовать дерево xExp (см. Комментарий xExp), изменяя при этом «x» apos; значение (это определение во входном выражении, но будет выходной переменной 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. Как я могу очистить этот xExp для разрешения & x; роль переменной случая? Кто-нибудь может объяснить всю картину этой ошибки?

PS: я безуспешно пытался использовать семейство замещающих * методов изTreeApi но мне не хватает основ, чтобы понять его значение.

Ответы на вопрос(1)

Ваш ответ на вопрос