Надежность сопоставления образцов деревьев с квазицитатами
У меня есть макрос, и часть этого макроса состоит в замене каждого вызова определенного метода чем-то другим. Для этого я использую Transformer
и стараться соответствовать каждому Tree
который входит в transform
метод против квазицитаты. Когда я пишу это, как показано ниже, это похоже на работу.
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)
???
}
}
Но я думал, что вы всегда должны использовать полностью определенные имена в макросах, иначе у вас могут возникнуть проблемы. Так что я написал это как q"_root_.mypackage.myobject.mymethod[..$_]($value)"
, но тогда это больше не соответствует и призывы к mymethod
больше не получил замену.
Я также посмотрел на предложение в scala docs о цитировании символов, но я не мог заставить это работать.
Поэтому мой вопрос: будет ли этот код (с q"mypackage.myobject.mymethod[..$_]($value)"
) всегда заменяйте все звонки на mymethod
и никогда не заменять какие-либо другие вызовы методов? И если нет, как я могу сделать его более надежным?
1 ответ
Макросы scala.reflect не гигиеничны, поэтому теоретически q"mypackage.myobject.mymethod[..$_]($value)"
мог быть подобран кем-то еще.
Я бы предложил сопоставить этот метод с q"..$mods def $name[..$tparams](...$paramss): $tpeopt = $expr"
(при условии, что это определение, а не объявление). Вы можете добавить проверки на name
,
Другое решение - пометить метод с аннотацией и удалить его в макро фазе.