2012-12-07 25 views
8

क्या स्केल 2.10 में एक विधि परिभाषा पेड़ (यानी, DefDef) के बाईं ओर MethodSymbol को चालू करने का कोई सुविधाजनक तरीका है?एक विधि प्रतीक और शरीर से एक विधि परिभाषा पेड़ बनाना

उदाहरण के लिए, मान लीजिए कि मैं एक मैक्रो बनाना चाहता हूं जो एक विशेषता का एक उदाहरण लेगा और कुछ डीबगिंग कार्यक्षमता के साथ उस विशेषता के सभी तरीकों को लपेट लेगा। निम्नलिखित मैं लिख सकते हैं:

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 

    //... 
} 

मैं एक नई अज्ञात वर्ग विशेषता को लागू करता है में इन तरीकों चिपके हुए और फिर उस वर्ग आप अगर आप एक पूरा काम कर उदाहरण here पा सकते हैं instantiating की बोरिंग व्यापार elided है ' रुचि रखते हैं

अब मैं यह लिख सकते हैं, उदाहरण के लिए:

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 

तो यह काम करता है, लेकिन केवल बहुत सरल में मामलों, यह नहीं होगा यदि विशेषता पैरामीटर सूची के साथ तरीकों, पहुँच संशोधक, एनोटेशन के साथ है, आदि

जो मैं वास्तव में चाहता हूं वह एक ऐसा कार्य है जो एक विधि प्रतीक और नए शरीर के लिए एक पेड़ लेगा और DefDef लौटाएगा। मैं हाथ से एक लिखना शुरू किया है, लेकिन यह इस तरह बारीकियों सामान का एक बहुत शामिल है:

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

कौन सा, कष्टप्रद वर्बोज़, और त्रुटि प्रवण है। क्या मुझे नए प्रतिबिंब एपीआई में ऐसा करने के लिए कुछ अच्छा तरीका याद आ रहा है?

उत्तर

4

मेरे सबसे अच्छे ज्ञान के लिए, प्रतीक से एक परिभाषित पेड़ पर जाने का कोई मानक तरीका नहीं है।

आपकी सर्वश्रेष्ठ शर्त शायद c.enclosingRun.units के माध्यम से फिर से शुरू हो जाएगी, unit.body पेड़ों में से प्रत्येक में आप जितनी बार जाते हैं। यदि आपको DefDef दिखाई देता है, जिसमें आपके प्रतीक के बराबर symbol है, तो आप अपने गंतव्य तक पहुंच गए हैं। upd। इसे पुन: उपयोग करने से पहले duplicate परिभाषित पेड़ को मत भूलना!

यह तकनीक दुनिया में सबसे सुविधाजनक चीज़ होने से बहुत दूर है, लेकिन इसे काम करना चाहिए।

+0

धन्यवाद (और +1), लेकिन क्या होगा यदि मैं जिस विशेषता को लपेटना चाहता हूं वह लाइब्रेरी से है? उस मामले में मैं उपर्युक्त दृष्टिकोण से फंस गया हूं, है ना? –

+1

आह मैं देखता हूं कि आपका क्या मतलब है। आप इस एपीआई का उपयोग कर सकते हैं: https://github.com/scalamacros/kepler/blob/0acb8a30c379f268e8a3e1340504530493a1a1dc/src/reflect/scala/reflect/api/Trees.scala#L2480। हमने इसे 2.10.1 में बहिष्कृत कर दिया है, लेकिन आप इसे देख सकते हैं कि इसे कैसे कार्यान्वित किया गया है: https://github.com/scalamacros/kepler/blob/0acb8a30c379f268e8a3e1340504530493a1a1dc/src/reflect/scala/reflect/internal/Trees.scala#L975 । –

2

आप निम्न का प्रयास कर सकते हैं। यह एकाधिक पैरामीटर और करीबी कार्यों और टाइप पैरामीटर के साथ काम करता है;)

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

'डेफडिफ (सीएम, पेड़)' भी है जो वही करता है, लेकिन जैसा कि नीचे बताया गया है, इस विधि को 'टाइपडिफ (सीएम)' और 'वैलडिफ (सीएम)' के साथ हटा दिया गया है। upd। यह वही नहीं करता है, क्योंकि आपका कोड मौजूदा संशोधकों को छोड़ देता है। –

+0

ओपी की गलती पर मेरी टिप्पणियां भी देखें: https://gist.github.com/4234441। आपके कोड में एक ही सूक्ष्म समस्या है क्योंकि वह कोड करता है। –

+0

धन्यवाद यूजीन। मैंने तदनुसार अपना जवाब अपडेट किया। यह मेरे कुछ मैक्रोज़ पर गंदे कंपाइलर दुर्घटनाओं के साथ कुछ मुद्दों को समझा सकता है। – Leo