8

マクロを使用して Scala XML リテラルを変換したいと考えています。(XML を使用した文字列リテラルではなく、実際の XML リテラル)。私の知る限り、XML リテラルは実際には AST レベルで言語に組み込まれておらず、パーサーで脱糖されています。興味深いことに、これはうまくいきます:

case q"<specificTag></specificTag>" => ... // succeeds for specificTag with no
                                           // attributes and children

しかし、明らかに、任意の xml をそのように一致させることは不可能であるため、これはまったく役に立ちません。何かのようなもの

case q"<$prefix:$label ..$attrs>$children</$prefix:$label>" => ...

パターン内で同じ変数を 2 回バインドする必要があるため、機能しません。

このような xml リテラル式のツリーを出力すると、実際には脱糖バージョンが得られます。例えば。

new _root_.scala.xml.Elem(null,"specificTag",_root_.scala.xml.Null,$scope,false)

しかし、これを一致させようとすると失敗します:

case q"new _root_.scala.xml.Elem(..$params)" => ... // never succeeds

私は混乱しています!私の質問は: scala マクロで任意の xml リテラルを確実に一致させる方法はありますか? さらに: 定数 xml の準引用符でサポートされているのに、desugared 値ではサポートされていないのはなぜですか?

4

2 に答える 2

2

xml はブロックでラップされ、マクロは として呼び出されrename( <top><bottom>hello</bottom></top> )ます。準引用符で構築されたものではなく、入ってくるツリーを見て気づいた。

以前にあなたの質問を見たとき、私はこの問題を提出しました。私のSOがそれであるかどうかはわかりません。SSsbtでぶつけてみました。おそらく関係のない別のSOの問題があります。

  class Normalizer(val c: Context) {
    import c.universe._ 
    def impl(e: c.Tree) = e match {
      case Block(List(), Block(List(), x)) => x match {
        case q"new scala.xml.Elem($prefix, $label, $attrs, $scope, $min, $t)" =>
          Console println s"Childed tree is ${showRaw(e)}" 
          val b = t match {
            case Typed(b, z) => c.untypecheck(b.duplicate)
            case _           => EmptyTree
          } 
          val Literal(Constant(tag: String)) = label
          val x = c.eval(c.Expr[NodeBuffer](b))
          //q"""<${tag.reverse}>..$x</${tag.reverse}>"""  // SO
          e
        case q"new scala.xml.Elem($prefix, $label, $attrs, $scope, $min)" =>
          Console println s"Childless tree is ${showRaw(e)}" ; e
        case _ => Console println s"Tree is ${showRaw(e)}" ; e
      }
      case _ => Console println s"Nonblock is ${showRaw(e)}" ; e
    }
  }
于 2014-04-02T07:46:38.547 に答える