2015-09-17 18 views
7

Bu yüzden bir işlev üzerinde ek açıklama (DefDef) var. Bu notun parametreleri var. Ancak, parametrelerin yapıcıdan nasıl alınacağı konusunda kafam karıştı.Scala Macro Annotation öğesinden parametre alma

Kullanım örneği:

class Foo(b: Boolean) extends StaticAnnotation { 
    def macroTransform(annottees: Any*) = macro Foo.impl 
} 

object Foo { 
    def impl(c: whitebox.Context)(annottees: c.Tree*): c.Expr[Any] = { 
    import c.universe._ 
    //how do I get value of `b` here??? 
    c.abort(c.enclosingPosition, "message") 
    } 
} 

cevap

7

Bunun neresi:

val b: Boolean = c.prefix.tree match { 
    case q"new Foo($b)" => c.eval[Boolean](c.Expr(b)) 
} 

Bütünlük adına bu tam kaynağıdır: Burada

class TestMacro { 
    @Foo(true) 
    def foo(): String = "" 
    foo 
} 

ek açıklama için kod

import scala.reflect.macros.Context 
import scala.language.experimental.macros 
import scala.annotation.StaticAnnotation 
import scala.annotation.compileTimeOnly 
import scala.reflect.api.Trees 
import scala.reflect.runtime.universe._ 

class Foo(b: Boolean) extends StaticAnnotation { 
    def macroTransform(annottees: Any*) :Any = macro FooMacro.impl 
} 

object FooMacro { 
    def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { 
    import c.universe._ 
    val b: Boolean = c.prefix.tree match { 
     case q"new Foo($b)" => c.eval[Boolean](c.Expr(b)) 
    } 
    c.abort(c.enclosingPosition, "message") 
    } 
} 
+0

Bu çözüm ilginç ancak bazı nedenlerden dolayı bana “hacky” gibi görünüyor. Ayrıca, "B" türünde herhangi bir türden değil, Boolean türünde olmak istiyorum. Birisi ''Foo (“ AAA ”)' 'diyebilir ve kodlarının kurucunun imzasına bakarak derleneceğini düşünebilir. Ayrıca, daha fazla argüman eklemeye karar verirsem daha kafa karıştırıcı olur. Ama bu çözüm işe yarıyor, teşekkürler! –

+0

Kaygılarınızı yansıtmak için yanıt düzenlendi. –

+0

Bu kod şimdi derlenmiyor. Parametre türünü Boole'den Any'a değiştirdiğinizde, her şey yolunda. Hata iletisi şöyledir: '' Null türündeki bir ifade, örtük dönüştürme için uygun değil'' –

1

İsteğe bağlı olarak adlandırılan argümanlara sahip bir statik ek açıklama kullanmak isterseniz, Federico'nın tekniğinde bir varyasyon gösteren bir yanıttır. Bu durumda, vaka eşleme ifadesindeki olası çağrı ifadelerini dikkate almanız gerekir. İsteğe bağlı bir argüman açıkça adlandırılmış olabilir, bir isim olmadan verilebilir veya mevcut olmayabilir. Bunların her biri, aşağıda gösterildiği gibi, c.prefix.tree'da ayrı bir model olarak derleme zamanında ortaya çıkar. İşte

@compileTimeOnly("Must enable the Scala macro paradise compiler plugin to expand static annotations") 
class noop(arg1: Int, arg2: Int = 0) extends StaticAnnotation { 
    def macroTransform(annottees: Any*): Any = macro AnnotationMacros.noop 
} 

class AnnotationMacros(val c: whitebox.Context) { 
    import c.universe._ 

    // an annotation that doesn't do anything: 
    def noop(annottees: c.Expr[Any]*): c.Expr[Any] = { 
    // cases for handling optional arguments 
    val (arg1q, arg2q) = c.prefix.tree match { 
     case q"new noop($arg1, arg2 = $arg2)" => (arg1, arg2) // user gave named arg2 
     case q"new noop($arg1, $arg2)" => (arg1, arg2)   // arg2 without name 
     case q"new noop($arg1)" => (arg1, q"0")    // arg2 defaulted 
     case _ => c.abort(c.enclosingPosition, "unexpected annotation pattern!") 
    } 

    // print out the values 
    println(s"arg1= ${evalTree[Int](arg1q)} arg2= ${evalTree[Int](arg2q)}") 

    // just return the original annotee: 
    annottees.length match { 
     case 1 => c.Expr(q"{ ${annottees(0)} }") 
     case _ => c.abort(c.enclosingPosition, "Only one annottee!") 
    } 
    } 

    def evalTree[T](tree: Tree) = c.eval(c.Expr[T(c.untypecheck(tree.duplicate))) 
} 

o isimler arg2 bir örnek çağırma olduğunu ve bu yüzden ilk desen maç olacak - case q"new noop($arg1, arg2 = $arg2)" - Yukarıda:

object demo { 
    // I will match this pattern: case q"new noop($arg1, arg2 = $arg2)" 
    @noop(1, arg2 = 2) 
    trait someDeclarationToAnnotate 
} 

Not Ayrıca, çünkü bu desenler çalışma biçimi nedeniyle, etmelisin Makro kodu içinde varsayılan argüman değerini açıkça belirtin, ki bu maalesef biraz hacky, ama nihai değerlendirme sınıfı sizin için mevcut değil.

Bir deneme olarak, aslında evalTree[scope.of.class.noop](c.prefix.tree) numaralı telefonu arayarak sınıfı oluşturmayı denedim, ancak Scala derleyici bir hata atar, çünkü ek açıklama makro kodunun içerisindeki ek açıklamalara yapılan bir başvuru geçersiz sayılır.

İlgili konular