2016-07-14 3 views
2

제 3 자 어노테이션 전 처리기에서 생성 한 일부 Java 클래스를 기반으로 스칼라 클래스를 작성하려고합니다.매크로 어노테이션의 인수로 클래스를 사용할 수 있습니까?

내가 예를 들어 주석 객체에서 클래스 "포인트", 수 있도록하고 싶습니다 :

@MyAnnotation(classOf[GeneratedJavaClass]) object MyObject 

또는

@MyAnnotation object MyObject extends PlaceHolderTrait[GeneratedJavaClass] 

내가 실제 매크로 구현에있어 일단

, GeneratedJavaClass를 반영하여 MyObject의 구현을 빌드하는 데 사용할 구성원을 찾습니다.

지금까지 시작점은 https://github.com/travisbrown/type-provider-examples/blob/master/rdfs-public/src/main/scala/public/PrefixGenerator.scala을 기준으로합니다.

은 내가 주석에 인자로 클래스 [T]를 걸릴 수 있습니다 방법을 이해하고 Apply(Select(Apply(_, List(TypeApply(_, List(catalog)))), _), _)c.macroApplication에 일치하지만 내가 할 유형이 TypeApply(_, List(Trees$Ident)입니다 시도한 내가 얻을 수있는 방법이 표시되지 않습니다 클래스 (classOf [T]가 리터럴이 아닙니다.)를 가정합니다.

대안으로 나는 개체 확장이있는 특성에서 원하는 유형을 추출하려고한다고 생각했습니다. case List(q"object $name extends PlaceHolderTrait[$parent] { ..$body }")에 대한 annotee를 매치했지만 나무 $ Ident로 끝나고 참조되는 클래스를 얻는 방법을 모르겠습니다.

아마도 정규화 된 이름의 String을 전달하고 클래스를 가져 오기 위해 리플렉션을 사용할 수 있지만 더 나은 대안을 기대하고있었습니다. 클래스를 지정하는 두 가지 대안에 묶여 있지 않다는 점에 유의하십시오.이 두 가지 옵션은 제가 생각해 낼 수있는 두 가지 옵션입니다.

답변

1

좋아, 마지막으로 뭔가 작업을 가지고,기준나는 타일러에서 달리는 단계에서 달리지 않았으므로 타입이 주어지기를 기대하는 것이 약간 바보라는 것을 깨달았다. 다음과 같이 매크로 API를, 당신은 나무에 TYPER을 실행할 수 있습니다 그러나 typeCheck 방법을 제공한다 :

class AnnotationArgument[T] extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro AnnotationArgumentImpl.impl 
} 

class AnnotationArgumentImpl(val c: blackbox.Context) { 

    import c.universe._ 

    def impl(annottees: c.Expr[Any]*): c.Tree = { 
     val macroTypeWithArguments = c.typeCheck(q"${c.prefix.tree}").tpe // my.package.AnnotationArgument[my.package.MyClass] 
     val annotationClass: ClassSymbol = macroTypeWithArguments.typeSymbol.asClass // my.package.AnnotationArgument 
     val annotationTypePlaceholder: Type = annotationClass.typeParams.head.asType.toType // T 
     val argumentType: Type = annotationTypePlaceholder.asSeenFrom(args, annotationClass) // my.package.MyClass 

     println(s"the argument's type is $argumentType") 


    q"..${annottees}" 
    } 
} 

import my.package.MyClass 
@AnnotationArgument[MyClass] 
class AnnotationArgumentTestClass 
+0

다른 사람이 이것을 못하게하는 추악한 방법이 있다면, 저는 제 대답을 받아들이지 않을 것이고, 내 경우에는 잘 작동합니다. –

0

다른 생각 :

사용하는 다른 클래스 주석 저장 클래스 정보

class AnnotationArgumentClass[T](clazz: Class[T]) extends StaticAnnotation 

class AnnotationArgument extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro AnnotationArgumentImpl.impl 
} 

class AnnotationArgumentImpl(val c: blackbox.Context) { 

    import c.universe._ 

    def impl(annottees: c.Expr[Any]*): c.Tree = { 
    val classValue = annottees.head.tree match { 
     case x: MemberDefApi => x.mods.annotations collectFirst { 
     case q"new $annotation($classValue)" => classValue 
     } 
    } 

    /*edit :*/ 
    val x = (c.eval(c.Expr[Type](c.typecheck(classValue.get)))) 
    println(x.typeSymbol.fullName) 

    q"..${annottees}" 
    } 
} 

시험 :

package aaa 
class AAA 

//

import aaa.AAA 
@AnnotationArgument 
@AnnotationArgumentClass(classOf[AAA]) 
class AnnotationArgumentTestClass 
+0

내가 찾을 수 없습니다'얻을 : 타입 MyType'을 매크로를 실행하려고 할 때, 아마도 당신의 예는 때문에 일 Int는 임포트 될 필요가 없다. –

+0

) : 그렇습니다. 왜냐하면'Int'는 import가 필요 없기 때문에'typecheck'를 필요로합니다. –