2012-12-07 4 views
8

MethodSymbol을 스칼라 2.10의 메서드 정의 트리 (즉, DefDef)의 왼쪽으로 편리하게 전환 할 수 있습니까?메서드 기호와 본문에서 메서드 정의 트리 만들기

예를 들어, 특성의 인스턴스를 취해 모든 특성의 메소드를 일부 디버깅 기능으로 포장하는 매크로를 작성한다고 가정합니다. 내가 쓸 수있는 다음과 같은 : 나는 특성을 구현하는 새로운 익명 클래스에서이 방법을 고집하고 해당 클래스 - 당신이 경우 전체 작업 예를 here을 찾을 수 있습니다 인스턴스의 지루한 사업을 생략 한

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 

    //... 
} 

' 관심이 다시.

이 지금은 예를 들어,이를 작성할 수 있습니다

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, ...) 

. 새 Reflection API에서이 작업을 수행하는 데 더 좋은 방법이 없습니까?

답변

4

내가 알고있는 한, 심볼에서 정의 트리로가는 표준 방법은 없습니다.

가장 좋은 방법은 c.enclosingRun.units을 반복하고 각각의 unit.body 트리를 반복하는 것입니다. 기호가 symbolDefDef이 표시되면 목적지에 도달했습니다. upd. 다시 사용하기 전에 정의 된 트리 duplicate을 잊지 마세요!

이 기술은 세계에서 가장 편리한 것으로 멀리 떨어져 있지만 작동해야합니다.

+0

감사합니다. (+1)하지만 랩핑하려는 특성이 라이브러리에 있다면 어떻게 될까요? 그 경우 나는 위의 접근법에 갇혀있다. –

+1

아, 무슨 뜻인지 알 겠어. 이 API는 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

같은 것을하는'DefDef (sym, tree)'도 있지만 아래에 언급했듯이이 메소드는'TypeDef (sym)'및'ValDef (sym)'와 함께 더 이상 사용되지 않습니다. upd. 코드가 기존 수정자를 생략하는 것으로 보이기 때문에 동일한 작업을 수행하지 않습니다. –

+0

OP의 요지에 대한 의견도 참조하십시오 : https://gist.github.com/4234441. 코드에는 코드와 동일한 미묘한 문제가 있습니다. –

+0

감사합니다. 유진. 그에 따라 내 대답을 업데이 트되었습니다. 이것은 일부 매크로에 불쾌한 컴파일러 충돌과 관련된 몇 가지 문제점을 설명 할 수 있습니다. – Leo