Czy istnieje wygodny sposób przekształcania obiektu MethodSymbol
w lewą stronę drzewa definicji metody (to jest, DefDef
) w Scali 2.10?Tworzenie drzewa definicji metody z symbolu metody i obiektu
Załóżmy na przykład, że chcę utworzyć makro, które zajmie instancję cechy i zawinie wszystkie te cechy, korzystając z niektórych funkcji debugowania. Mogę napisać następujące:
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
//...
}
Mam pomijana nudny biznes od przyklejania tych metod w nowej klasie anonimowej implementującej cechę, a następnie instancji klasy, które można znaleźć kompletny pracy przykład here jeśli was” jestem zainteresowany.
Teraz mogę napisać to na przykład:
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
Tak to działa, ale tylko w bardzo prostych przypadkach, to nie będzie, jeśli cecha ma metod z listami parametrów, z modyfikatorów dostępu, adnotacje, itd.
To, czego naprawdę chcę, to funkcja, która pobiera symbol metody i drzewo dla nowego obiektu i zwraca wartość DefDef
. Zacząłem pisać jedną ręką, ale to wymaga dużo fiddly rzeczy tak:
List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...)
Która jest denerwujące, gadatliwe i podatne na błędy. Czy brakuje mi lepszego sposobu na to w nowym interfejsie API Reflection?
Dzięki (i +1), ale co, jeśli cecha, którą chcę opakować, pochodzi z biblioteki? W takim razie utknąłem z podejściem powyżej, prawda? –
Ah Widzę, co masz na myśli. Możesz użyć tego interfejsu API: https://github.com/scalamacros/kepler/blob/0acb8a30c379f268e8a3e1340504530493a1a1dc/src/reflect/scala/reflect/api/Trees.scala#L2480. Usunęliśmy go w wersji 2.10.1, ale możesz sprawdzić, jak jest zaimplementowany: https://github.com/scalamacros/kepler/blob/0acb8a30c379f268e8a3e1340504530493a1a1dc/src/reflect/scala/reflect/internal/Trees.scala#L975 . –