scala AST — что такое литерал строковой константы и как мне это выяснить?

#scala #pattern-matching #abstract-syntax-tree #scala-macros

#scala #сопоставление с образцом #абстрактное синтаксическое дерево #scala-макросы

Вопрос:

Рассмотрим следующий фрагмент

 object Main {
  def main(args:Array[String]): Unit ={
    import Debugger.debug
    debug("Hello World")
    val x = 0
    debug(x)
    debug(1)
  }
}
  

Я хочу, чтобы это печаталось

 Hello World
x = 0
1
  

используя макрос:

 import scala.language.experimental.macros
import scala.reflect.macros._


object Debugger {
  val doDebug = true

  def debug(v : Any) :Unit = macro implDebug

  def implDebug(c:blackbox.Context)(v:c.Expr[Any]): c.Expr[Unit] ={
    import c.universe._

    if(doDebug) {
      v match {
        case Literal(Constant(_)) => reify{println(v.splice)}
        case _ =>
          println(v.tree)
          println(v.tree.getClass.getName)
          val rep = show(v.tree)
          val repTree = Literal(Constant(rep))
          val repExpr = c.Expr[String](repTree)
          reify{
            println(repExpr.splice   " = "   v.splice)
          }
      }
    }
    else reify{}
  }
}
  

Это выводит (компиляция запуск):

 [sbt compile bla bla]
"Hello World"
scala.reflect.internal.Trees$Literal
x
scala.reflect.internal.Trees$Ident
1
scala.reflect.internal.Trees$Literal
[info] Running Main 
"Hello World" = Hello World
x = 0
1 = 1
  

итак… по-видимому, «Hello World» является литералом, но не соответствует шаблону литерала (также пробовалось case Literal(_) с одинаково неудовлетворительными результатами).

Почему? И что мне нужно сопоставить вместо этого?

Комментарии:

1. Вы пробовали сопоставлять v.tree вместо этого?

2. @Actorclavilis Такая глупая вещь. -.- Спасибо. Хотите уточнить, чтобы я мог принять это как ответ?

Ответ №1:

Ваш implDebug метод принимает a c.Expr[Any] , который является оболочкой для a c.Tree . Literal(Constant(...)) является правильным средством сопоставления для значения литерального дерева, но поскольку вы хотите, чтобы оно соответствовало дереву, вам следует использовать v.tree match {...} вместо этого.