MacroAnnotation 从方法的类型成员中删除注释
MacroAnnotation to remove annotation from method's type member
我正在学习如何编写 Scala 宏,并编写了一个宏注释,用于从带注释的函数的类型参数中删除注释。在这里。
要删除的注释:
class garbage extends StaticAnnotation
执行宏删除注解:
@compileTimeOnly("Compile-time only annotation")
class removeGarbage extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro impl
}
object removeGarbage {
def impl(c: whitebox.Context)(annottees: c.Tree*) = {
import c.universe._
println(annottees)
val expandee = annottees.toList collect {
case q"$mods def $templatename[..$typeparams](...$paramss): $tpt = $body" =>
val modifiedParams = typeparams collect {
case q"$mods type $name[..$args] = $tpt" =>
val modifiedMods = mods match {
case Modifiers(flags, privateWithin, annots) =>
Modifiers(flags, privateWithin, annots.filter(_ == q"new garbage()"))
}
q"$modifiedMods type $name[..$args] = $tpt"
}
q"$mods def $templatename[..$modifiedParams](...$paramss): $tpt = $body"
case annottee =>
c.abort(c.enclosingPosition, s"$annottee cannot be annotated with @removeGarbage. Only def methods are allowed")
}
println(expandee)
q"..$expandee"
}
}
测试方法:
trait Test{
@removeGarbage
def someMethod[@garbage Source, G[_]](i: Int): G[List[Int]]
}
这似乎工作正常。为了检查它,我比较了添加了 println(annottees)
和 println(expandees)
:
的日志
List(def someMethod[@new garbage() Source, G[_]](i: Int): G[List[Int]])
List(def someMethod[Source, G[_]](i: Int): G[List[Int]])
关于解决方案的问题看起来很难阅读。也许我没有充分发挥准引号的潜力。有没有办法简化宏的实现(可能更广泛地使用准引号...)?
宏代码难读也没关系:)
这就是元编程不应成为第一工具的原因。
我看不出如何显着减少您的代码。
你可以替换
val modifiedMods = mods match {
case Modifiers(flags, privateWithin, annots) =>
Modifiers(flags, privateWithin, annots.filter(_ == q"new garbage()"))
}
和one-liner
val modifiedMods = mods.mapAnnotations(_.filter(_ == q"new garbage()"))
如果您在许多宏中继续执行相同的一组转换,您可以类似地定义辅助方法,例如 mapDef
、mapTypeParams
...
如果准引号变得太麻烦,您 可以使用 ClassDef
、Template
、DefDef
...代替准引号或在方便时将它们与准引号混合使用。
(此类问题通常 https://codereview.stackexchange.com/ although metaprogramming seems to be not so 在那里很流行。)
我正在学习如何编写 Scala 宏,并编写了一个宏注释,用于从带注释的函数的类型参数中删除注释。在这里。
要删除的注释:
class garbage extends StaticAnnotation
执行宏删除注解:
@compileTimeOnly("Compile-time only annotation")
class removeGarbage extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro impl
}
object removeGarbage {
def impl(c: whitebox.Context)(annottees: c.Tree*) = {
import c.universe._
println(annottees)
val expandee = annottees.toList collect {
case q"$mods def $templatename[..$typeparams](...$paramss): $tpt = $body" =>
val modifiedParams = typeparams collect {
case q"$mods type $name[..$args] = $tpt" =>
val modifiedMods = mods match {
case Modifiers(flags, privateWithin, annots) =>
Modifiers(flags, privateWithin, annots.filter(_ == q"new garbage()"))
}
q"$modifiedMods type $name[..$args] = $tpt"
}
q"$mods def $templatename[..$modifiedParams](...$paramss): $tpt = $body"
case annottee =>
c.abort(c.enclosingPosition, s"$annottee cannot be annotated with @removeGarbage. Only def methods are allowed")
}
println(expandee)
q"..$expandee"
}
}
测试方法:
trait Test{
@removeGarbage
def someMethod[@garbage Source, G[_]](i: Int): G[List[Int]]
}
这似乎工作正常。为了检查它,我比较了添加了 println(annottees)
和 println(expandees)
:
List(def someMethod[@new garbage() Source, G[_]](i: Int): G[List[Int]])
List(def someMethod[Source, G[_]](i: Int): G[List[Int]])
关于解决方案的问题看起来很难阅读。也许我没有充分发挥准引号的潜力。有没有办法简化宏的实现(可能更广泛地使用准引号...)?
宏代码难读也没关系:) 这就是元编程不应成为第一工具的原因。
我看不出如何显着减少您的代码。
你可以替换
val modifiedMods = mods match {
case Modifiers(flags, privateWithin, annots) =>
Modifiers(flags, privateWithin, annots.filter(_ == q"new garbage()"))
}
和one-liner
val modifiedMods = mods.mapAnnotations(_.filter(_ == q"new garbage()"))
如果您在许多宏中继续执行相同的一组转换,您可以类似地定义辅助方法,例如 mapDef
、mapTypeParams
...
如果准引号变得太麻烦,您 ClassDef
、Template
、DefDef
...代替准引号或在方便时将它们与准引号混合使用。
(此类问题通常 https://codereview.stackexchange.com/ although metaprogramming seems to be not so 在那里很流行。)