2014-01-29 24 views
1

我試圖通過使用隱式宏來收集範圍中存在的所有標識符,但我無法找到找到它們的優雅方法。收集範圍內的所有標識符

val endPos = c.enclosingPosition.endOrPoint 
val mNames = c.enclosingMethod 
      .collect {case v: ValDef => v} 
       .filter(_.pos.start > endPos) 
       .map {case ValDef(_, name, _, _) => Ident(name)} 
val cNames = c.enclosingClass 
      .collect {case ValDef(_, name, _, _) => Ident(name)} 
val names = mNames ++ cNames 

先前捕獲的所有變量,即使它們在不同的方法定義,但我需要一種方法來過濾從cNames發生在方法ValDefs。調用children看起來可能有效,但我仍然從其他塊中獲取ValDefs。

我的最終目標是能夠做到Logger.trace(),並記錄範圍內的所有變量。所以

def test() = { 
    val v = 2 
    val z = "fdsaf" 
    Logger.trace() 
} 

將登錄v: 2, z: "fdsaf"

編輯2:

import c.universe._ 
val callingPos = c.enclosingPosition 
val encMet = Option(c.enclosingMethod) 

val classElements = c.enclosingClass 
        .asInstanceOf[ImplDefApi] 
        .impl.children 
        .collect { 
    case v: Block => v.asInstanceOf[Tree] 
    case v: DefDef => v.asInstanceOf[Tree] 
    case v: ValDef => v.asInstanceOf[Tree] 
    case v: ModuleDef => v.asInstanceOf[Tree] 
} 

val classFields = classElements.collect {case [email protected](_, name, _, _) if !v.isEmpty => Ident(name)} 
val blockFields = classElements.collectFirst{ 
    case Block(body, ret) if positionIsInList(c)(body) => body.collect { 
     case [email protected](_, name, _, _) if v.pos precedes callingPos => Ident(name) 
    } 
}.getOrElse(List()) 
val methodFields = encMet 
        .map(_.collect {case [email protected](_, name, _, _) if v.pos precedes callingPos => Ident(name)}) 
        .getOrElse(List()) 

val names = classFields ++ blockFields ++ methodFields 

作品在大多數情況下,但未能上塊。

回答

2

不幸的是,這個用例目前不是Scala宏支持的。當然,正如你已經證明的那樣,一些或多或少工作的東西可以被鞭打(非常感謝這些例子!),但據我所知儘管沒有可靠的方法來實現你的目標。

在將來,我們也許能夠應對這種挑戰,但目前是阻止我們在此刻暴露這種API的技術限制。即使投射到編譯器內部,有時在棘手的情況下也有幫助,但這不會對此有所幫助。實際上,這正是Scala 2.11中我們棄用c.enclosingTree樣式API的原因:https://groups.google.com/forum/#!topic/scala-internals/nf_ooEBn6-k

如果你可以在你想達到什麼樣的闡述,我將很樂意幫助尋找到可能最終會被你的使用情況下非常有用的解決方法。

+0

我編輯了我的問題來解決我的最終目標,就在'編輯2'之前。我已經看到了你的拉動請求enclosingOwner,看起來它幾乎可以解決這個問題,但我無法弄清楚如何從'Symbol'中獲得'Tree'。 – user60561

+0

從符號中獲取樹是不可能的,因爲符號只是編譯器可用的定義表中的條目,沒有附加任何AST信息。這可能會在未來發生變化,但到目前爲止它不受支持。 –

+0

我不認爲現在可以編寫這種宏。查找範圍內最接近的內容是使用c.inferImplicitValue,但爲此,您需要將事物隱式化,並事先知道某種類型。 –