2013-08-30 19 views
7

Bu, benim previous question numaralı telefonumda bir takiptir.Oluşturulan makro yöntemindeki `this` işlevini kullanın.

Aşağıdaki kodun çalışmasını istiyorum. Bir makro oluşturulan yöntem oluşturmak mümkün istiyorum:

case class Cat() 

test[Cat].method(1) 

Nerede kendisi bir makro (a "vampire" method) kullanıyor üretilen yöntemin uygulanması:

// macro call 
def test[T] = macro testImpl[T] 

// macro implementation 
def testImpl[T : c.WeakTypeTag](c: Context): c.Expr[Any] = { 
    import c.universe._ 
    val className = newTypeName("Test") 

    // IS IT POSSIBLE TO CALL `otherMethod` HERE? 
    val bodyInstance = q"(p: Int) => otherMethod(p * 2)" 

    c.Expr { q""" 
    class $className { 
     protected val aValue = 1 

     @body($bodyInstance) 
     def method(p: Int): Int = macro methodImpl[Int] 

     def otherMethod(p: Int): Int = p 
    } 
    new $className {} 
    """} 
} 

// method implementation 
def methodImpl[F](c: Context)(p: c.Expr[F]): c.Expr[F] = { 
    import c.universe._ 

    val field = c.macroApplication.symbol 
    val bodyAnnotation = field.annotations.filter(_.tpe <:< typeOf[body]).head 
    c.Expr(q"${bodyAnnotation.scalaArgs.head}.apply(${p.tree.duplicate})") 
} 

Bu kod ile derlenmeyecektir :

[error] no-symbol does not have an owner 
last tree to typer: This(anonymous class $anonfun) 
[error]    symbol: anonymous class $anonfun (flags: final <synthetic>) 
[error] symbol definition: final class $anonfun extends AbstractFunction1$mcII$sp with Serializable 
[error]     tpe: examples.MacroMatcherSpec.Test.$anonfun.type 
[error]  symbol owners: anonymous class $anonfun -> value <local Test> -> class Test -> method e1 -> class MacroMatcherSpec -> package examples 
[error]  context owners: value $outer -> anonymous class $anonfun -> value <local Test> -> class Test -> method e1 -> class MacroMatcherSpec -> package examples 
[error] 
[error] == Enclosing template or block == 
[error] 
[error] DefDef(// val $outer(): Test.this.type 
[error] <method> <synthetic> <stable> <expandedname> 
[error] "examples$MacroMatcherSpec$Test$$anonfun$$$outer" 
[error] [] 
[error] List(Nil) 
[error] <tpt> // tree.tpe=Any 
[error] $anonfun.this."$outer " // private[this] val $outer: Test.this.type, tree.tpe=Test.this.type 
[error]) 

bunun ne anlama geldiğini deşifre de çok kötü ama ben gövdesinde this.otherMethod başvuramaz gerçeği ile ilişkili olduğunu sanıyorum vampir yöntemi. Bunu yapmanın bir yolu var mı? Bu çalışırsa

, sonraki adımım otherMethod için uygulama bu tür olacaktır:

def otherMethod(p: Int) = new $className { 
    override protected val aValue = p 
} 
+0

gibi bir şey ben sadece [bir blog post] (http://meta.plasm.us/posts/2013/08/31/feeding- olarak bu soruna daha genel bir yanıt yazdık bizim-vampirler /). Eğer aradığınız şey varsa, yoğunlaştırılmış bir sürümü burada bir cevap olarak ekleyebilirim. –

cevap

2

"Bu" c.prefix.tree olarak genellikle mevcuttur. Bu yüzden belki

val bodyInstance = 
    q"(p: Int) => ${c.prefix.tree}.otherMethod(p * 2)" 
İlgili konular