将类作为参数传递给scala中的StaticAnnotation宏

时间:2016-05-16 11:06:33

标签: scala macros

我想将一个类作为参数传递给Scala中的StaticAnnotation宏,让我们说我需要一个检查DateTime实例的宏:

class CheckDate(date: DateTime) extends StaticAnnotation {
    def macroTransform(annottees: Any*): Any = macro CheckDate.impl
}

object CheckDate {
    def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
        import c.universe._

        ???
}

并实施:

@CheckDate(new DateTime(...))
class Sth(...) {...}

如何从AST中检索DateTime实例?

1 个答案:

答案 0 :(得分:0)

经过一些调整后,我终于找到了一种方法来为scala中的StaticAnnotation宏检索更复杂的参数。

首先,我通过c.prefix.tree上的模式匹配提取了所有参数,实际上是指注释类,如下所示:

val params = c.prefix.tree match {
  case q"""new CheckDate(...$paramss)""" => paramss
  case _ => c.warning(NoPosition, "Oops, something went terribly wrong!")
}

我尝试通过使用showRaw(params)打印树来检查树的参数,并且有两种可能的模式(带或不带参数名称):

List(List(AssignOrNamedArg(
Ident(TermName("date")),
Apply(Select(New(Ident(TypeName("DateTime"))), termNames.CONSTRUCTOR),
List(Literal(Constant(2016)), Literal(Constant(5)), Literal(Constant(10)))))))

List(List(Apply(
Select(New(Ident(TypeName("DateTime"))), termNames.CONSTRUCTOR), 
List(Literal(Constant(2016)), Literal(Constant(5)), Literal(Constant(11))))))

为了使用DateTime对象,我们需要提取相应的字段并创建新的DateTime个实例:

val d: DateTime = params match {
   case List(List(AssignOrNamedArg(
   _, Apply(_, List(Literal(Constant(y)), Literal(Constant(m)), Literal(Constant(d))))))) =>
       new DateTime(y.asInstanceOf[Int], m.asInstanceOf[Int], d.asInstanceOf[Int], 0, 0)
   case List(List(Apply(_, List(Literal(Constant(y)),
   Literal(Constant(m)), Literal(Constant(d)))))) =>
       new DateTime(y.asInstanceOf[Int], m.asInstanceOf[Int], d.asInstanceOf[Int], 0, 0)
实际上很多样板,但结果非常有效。关键是要检查要解析的结构的AST并为其创建适当的案例。