4

I'm trying to use macro annotations in scala, where my macro annotation would take an argument of another type. It would then use scala reflection to look at the passed in type, and add some methods as appropriate.Eg.

trait MyTrait {
  def x: Int
  def y: Float
}

@MyAnnotation class MyClass //<-- somehow, this annotation should reference MyTrait

class MyAnnotation(val target: Any) extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro MyAnnotationImpl.impl
}
object MyAnnotationImpl {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    // if I can get a handle on the type MyTrait in here
    // then I can call .members on it, etc.
    ...
  }
}

Basically, the same thing as Using Scala reflection in Scala macros, except using macro annotations. However, when I try to template my macro annotation with a TypeTag

class MyAnnotation[T](val target: Any) extends StaticAnnotation {
  def macroTransform[T](annottees: Any*) = macro MyAnnotationImpl.impl[T]
}
object MyAnnotationImpl {
  def impl[T: c.WeakTypeTag](c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    ...
  }
}

I get

[error] /Users/imran/other_projs/learn_macros/macros/src/main/scala/com/imranrashid/oleander/macros/MacrosWithReflection.scala:7: macro annotation has wrong shape:
[error]   required: def macroTransform(annottees: Any*) = macro ...
[error]   found   : def macroTransform[T](annottees: Any*) = macro ...
[error] class MyAnnotation[T](val target: Any) extends StaticAnnotation {
[error]       ^

I've also tried to make the type an argument to my annotation, so I would use it like @MyAnnotation(MyTrait) class Foo .... I can extract the name as a String with something like

val targetTrait = c.prefix.tree match {
  case Apply(Select(New(Ident(_)), nme.CONSTRUCTOR), List(Ident(termName))) => termName
}

but, I'm not sure what I can do w/ that String to get back the full type. I've also tried variants like @MyAnnotation(typeOf[MyTrait]) class Foo ..., and then use c.eval on the typeOf inside my macro, but that doesn't compile either.

4

2 回答 2

6

在宏天堂 2.0.0-SNAPSHOT 中,我们有一种非常棘手的方式来访问宏注释的类型参数(当我们有专门的 API 时情况会有所改善,但现在很难为 scala-reflect 引入新功能.jar 在宏天堂,所以现在的 API 有点粗糙)。

现在有必要在注解类上指定类型参数,而不是在macroTransform方法上声明任何类型参数。然后,在宏扩展中,访问c.macroApplication并提取与传递的类型参数对应的无类型树。之后,c.typeCheck按照Can't access Parent's Members while handling Macro Annotations中的描述进行操作。

于 2013-11-05T21:39:32.453 回答
0

正如 Eugene 在他的回答中指出的那样,可以在整个宏应用程序的树上进行匹配。与每个 Scala 方法一样,注释宏应用程序可以采用多个类型参数列表以及多个值参数列表。

考虑一个名为 的注解宏的宏应用test

    @test[A, B][C, D](a, b)(c, d) trait Foo

在实现中,test我们可以通过以下方式检查宏应用程序

    println(show(c.macroApplication))

这将导致:

    new test[A, B][C, D](a, b)(c, d).macroTransform(abstract trait Foo extends scala.AnyRef)

要从树中提取(类型/值)参数,您必须在树上进行模式匹配。可以在这个项目中找到任意数量的参数列表的解析器

使用这个解析器检索宏应用程序的第一个值参数就像

    val List(List(arg)) = MacroApp(c.macroApplication).termArgs
于 2015-05-26T17:39:37.953 回答