2012-12-07 13 views
8

MethodSymbol'u Scala 2.10'da bir yöntem tanımlama ağacının (ör. DefDef) sol tarafına döndürmenin kullanışlı bir yolu var mı? Örneğin, bir özelliğin bir örneğini alacak ve bu tüm trait yöntemlerini bazı hata ayıklama işlevleri ile dolduracak bir makro oluşturmak istediğimi varsayalım. Yazabilirim aşağıdaki: Ben özelliği uygulayan yeni bir anonim sınıfta bu yöntemleri yapışmasını ve daha sonra bu sınıf-sen eğer tam bir çalışma örneği here bulabilirsiniz nesnelleştirilme sıkıcı iş elided ettikBir yöntem sembolünden ve bir gövdeden bir yöntem tanımlama ağacı oluşturma

import scala.language.experimental.macros 
import scala.reflect.macros.Context 

object WrapperExample { 
    def wrap[A](a: A): A = macro wrap_impl[A] 

    def wrap_impl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = { 
    import c.universe._ 

    val wrapped = weakTypeOf[A] 
    val f = Select(reify(Predef).tree, "println") 

    val methods = wrapped.declarations.collect { 
     case m: MethodSymbol if !m.isConstructor => DefDef(
     Modifiers(Flag.OVERRIDE), 
     m.name, 
     Nil, Nil, 
     TypeTree(), 
     Block(
      Apply(f, c.literal("Calling: " + m.name.decoded).tree :: Nil), 
      Select(a.tree, m.name) 
     ) 
    ) 
    }.toList 

    //... 
} 

' ilgileniyorum.

Şimdi örneğin, bu yazabilirsiniz:

scala> trait X { def foo = 1; def bar = 'a } 
defined trait X 

scala> val x = new X {} 
x: X = [email protected] 

scala> val w: X = WrapperExample.wrap[X](x) 
w: X = [email protected] 

scala> w.foo 
Calling: foo 
res0: Int = 1 

scala> w.bar 
Calling: bar 
res1: Symbol = 'a 

Yani çalışıyor, ama sadece çok basit durumlarda-o alışkanlık özelliği erişim değiştiricileri, ek açıklamalarla parametre listeleri ile yöntemlerini, varsa,

Gerçekten istediğim bir yöntem sembolü ve yeni gövde için bir ağaç alacak ve bir DefDef döndürecektir. Ben elle tek yazmaya başladım, ama böyle keman bir sürü içerir: can sıkıcı ayrıntılı ve hataya açık olan

List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...) 

. Yeni Yansıma API'sinde bunu yapmanın daha güzel bir yolunu mu duyuyorum?

cevap

4

Bildiğim kadarıyla, bir sembolden tanımlayıcı bir ağaca gitmenin standart bir yolu yoktur.

En iyi bahsiniz, muhtemelen, c.enclosingRun.units aracılığıyla yinelemeniz ve unit.body ağaçlarının her birine yeniden girmenizdir. Sembolünüze eşit bir symbol olan bir DefDef görüyorsanız, hedefinize ulaştınız demektir. Post. Yeniden tanımlamadan önce tanımlayan ağaç duplicate unutma!

Bu teknik, dünyadaki en uygun şey olmaktan çok uzaktır, ancak çalışmalıdır.

+0

Teşekkürler (ve +1), ama sarmak istediğim özellik kütüphaneden mi geliyor? Bu durumda, yukarıdaki yaklaşıma takıldım, değil mi? –

+1

Ah Ne demek istediğini görüyorum. Bu API'yi kullanabilirsiniz: https://github.com/scalamacros/kepler/blob/0acb8a30c379f268e8a3e1340504530493a1a1dc/src/reflect/scala/reflect/api/Trees.scala#L2480. 2.10.1'de kullanımdan kaldırdık, ancak nasıl uygulandığına göz atabilirsiniz: https://github.com/scalamacros/kepler/blob/0acb8a30c379f268e8a3e1340504530493a1a1dc/src/reflect/scala/reflect/internal/Trees.scala#L975 . –

2

Aşağıdakileri deneyebilirsiniz. Bu, birden çok parametre ve kıvrımlı işlevler ve tür parametreleriyle çalışır;)

val methods = wrapped.declarations.collect { 
    case m: MethodSymbol if !m.isConstructor => DefDef(
    Modifiers(Flag.OVERRIDE), 
    m.name, 
    m.typeParams.map(TypeDef(_)), 
    m.paramss.map(_.map(ValDef(_))), 
    TypeTree(m.returnType), 
    Block(
     Apply(f, c.literal("Calling: " + m.name.decoded).tree :: Nil), 
     m.paramss.foldLeft(Select(a.tree.duplicate, m.name): Tree)((prev, params) => 
     Apply(prev, params.map(p => Ident(p.name))) 
    ) 
    ) 
) 
}.toList 
+0

Ayrıca, bunu yapan 'DefDef (sym, tree) 'da var, ancak aşağıda belirtildiği gibi, bu yöntem' TypeDef (sym) 've' ValDef (sym) 'ile birlikte kullanımdan kaldırılmıştır. Post. Aynı şeyi yapmaz, çünkü kodunuz mevcut değiştiricileri çıkarır gibi görünüyor. –

+0

Ayrıca OP'imin özgeçmişine yorumlarımı görün: https://gist.github.com/4234441. Kodunuz, bu kodun yaptığı aynı ince soruna sahip. –

+0

Teşekkürler Eugene. Cevabımı buna göre güncelledim. Bu, bazı makrolarımda kötü derleyici çökmeleriyle ilgili bazı sorunları açıklayabilir. – Leo

İlgili konular