2016-09-01 1 views
1

Ich habe ein Makro und Teil dieses Makros besteht darin, jeden Aufruf einer bestimmten Methode durch etwas anderes zu ersetzen. Um dies zu erreichen, verwende ich eine Transformer und versuche, alle Tree, die die transform-Methode gegen eine Quasiquote eintritt. Wenn ich es unten schreibe, scheint es zu funktionieren.Robustheit des Mustervergleichs Bäume mit Quasiquoten

package mypackage 

object myobject { 
    implicit def mymethod[T](t: Option[T]): T = ??? 
} 

object Macros { 
    import scala.language.experimental.macros 
    import scala.reflect.macros.blackbox.Context 

    def myMacro(c: Context)(expr: c.Tree): c.Tree = { 
    import c.universe._ 

    val transformer = new Transformer { 
     private def doSomething(value: c.Tree): TermName = { 
     ??? 
     } 
     override def transform(tree: c.Tree) = tree match { 
     case q"mypackage.myobject.mymethod[..$_]($value)" => 
      val result = doSomething(value) 
      q"$result" 
     case _ => super.transform(tree) 
     } 
    } 
    val transformed = transformer.transform(expr) 

    ??? 
    } 
} 

Aber ich dachte, Sie sollten immer voll qualifizierte Namen in Makros verwenden oder Sie könnten in Schwierigkeiten geraten. So schrieb ich es wie q"_root_.mypackage.myobject.mymethod[..$_]($value)", aber dann nicht mehr übereinstimmte und die Anrufe zu mymethod nicht mehr ersetzt.
Ich schaute auch auf den Vorschlag in the scala docs Symbole zu entmarkieren, aber ich konnte das auch nicht funktionieren.

Also meine Frage ist: wird dieser Code (mit q"mypackage.myobject.mymethod[..$_]($value)") immer alle Anrufe zu mymethod ersetzen und nie irgendwelche anderen Methodenaufrufe ersetzen? Und wenn nicht, wie kann ich es robuster machen?

Antwort

2

scala.reflect Makros sind nicht hygienisch, daher könnte theoretisch q"mypackage.myobject.mymethod[..$_]($value)" von jemand anderem abgeglichen werden.

Ich würde vorschlagen, diese Methode mit q"..$mods def $name[..$tparams](...$paramss): $tpeopt = $expr" übereinstimmen (vorausgesetzt, dass die Definition, nicht die Deklaration ist). Sie können Prüfungen unter name hinzufügen.

Eine andere Lösung besteht darin, eine Methode mit Annotation zu markieren und sie in der Makrophase zu entfernen.

+0

Wenn ich einen Methodenaufruf in einem 'Tree' finde, wie kann ich überprüfen, dass die Methode, die aufgerufen wird, eine bestimmte Anmerkung hat? –

+1

'mods' wird es enthalten. http://docs.scala-lang.org/overviews/quasiquotes/definition-details könnte nützlich sein. – dveim

+1

Okay, eine Alternative, die für mich funktioniert: 'methodCallFromTree.symbol.asMethod.annotations'. –