Использование макроса scala для манипулирования объявлением переменной - PullRequest
0 голосов
/ 08 марта 2019

Я хотел бы использовать макросы scala (v2.12.8) для манипулирования всеми объявлениями переменных данного блока.В этом примере добавить значение 23.

Например:

val myblock = mymanipulator {
    var x = 1
    x = 4
    var y = 1
    x + y
  }
print( myblock )

становится

{
  var x = (1).+(23);
  x = 4;
  var y = (1).+(23);
  x.+(y)
}

Для этого я реализовал mymanipulator следующим образом:

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.language.implicitConversions

object mymanipulator {
  def apply[T](x: => T): T = macro impl

  def impl(c: Context)(x: c.Tree) = { import c.universe._

    val q"..$stats" = x
    val loggedStats = stats.flatMap { stat =>

      stat match {
        case ValDef(mods, sym, tpt, rhs) => {
          List( q"var $sym : $tpt = $rhs + 23" )
        }

        case _ => {
          List( stat )
        }
      }

    }

    val combined = q"..$loggedStats"

    c.info(c.enclosingPosition, "combined: " + showRaw(combined), true)

    combined
  }
}

И я получаю эту информацию во время компиляции макроса:

Information:(21, 31) combined: {
  var x = (1).+(23);
  x = 4;
  var y = (1).+(23);
  x.+(y)
}
  val myblock = mymanipulator {

Но когда я выполняю mymanipulator с указанным выше блоком, я получаю это сообщение об ошибке:

Error:scalac: Error while emitting Test.scala
variable y

Эта ошибка возникает также, когда я изменяю реализацию, чтобы ничего не делать:

 stat match {
        case ValDef(mods, sym, tpt, rhs) => {
          List( q"var $sym : $tpt = $rhs" )
        }

        case _ => {
          List( stat )
        }
      }

Только когда я возвращаю stat, ошибка исчезает

 stat match {
    case ValDef(mods, sym, tpt, rhs) => {
       List( stat )
     }

     case _ => {
        List( stat ) 
      }
  }

Может кто-нибудь сказать мне, что я делаюнеправильно?Спасибо

1 Ответ

1 голос
/ 08 марта 2019

Вы должны отменить проверку дерева перед преобразованием

  object mymanipulator {
    def apply[T](x: => T): T = macro impl

    def impl(c: blackbox.Context)(x: c.Tree): c.Tree = {
      import c.universe._

      val q"..$stats" = c.untypecheck(x) // here
      val loggedStats = stats.flatMap { stat =>

        stat match {
          case ValDef(mods, sym, tpt, rhs) /*q"$mods var $sym : $tpt = $rhs"*/ => {
            List( q"$mods var $sym : $tpt = $rhs + 23" )
          }

          case _ => {
            List( stat )
          }
        }

      }

      val combined = q"..$loggedStats"

      c.info(c.enclosingPosition, "combined: " + showRaw(combined), true)

      combined
    }
  }

Требуется проверка макроса без проверки

Что не так с этим макросом def?

...