2013-07-15 8 views
7

ListTypeSymbolに戻す方法はありますか?Scalaマクロ:実行時に使用するTypeSymbolsのリストを取得する

私は何を達成しようとしていますが、このリストと同等の何かを与えマクロを書くことです:

scala> import scala.reflect.runtime.universe._ 
import scala.reflect.runtime.universe._ 

scala> case class MyClass1() 
defined class MyClass1 

scala> case class MyClass2() 
defined class MyClass2 

scala> val typeSymbols = List(typeOf[MyClass1].typeSymbol, typeOf[MyClass2].typeSymbol) 
typeSymbols: List[reflect.runtime.universe.Symbol] = List(class MyClass1, class MyClass2) 

は、ここに私の設定です:

私はこれらがその下fooという名前のパッケージを持っています定義された:

trait FooTrait 

case class Bar() extends FooTrait 

case class Bar() extends FooTrait 

ここFooTraitを拡張fooの下のクラスのすべてのタイプのシンボルを取得し、私のマクロです:

枚の
def allTypeSymbols_impl[T: c.WeakTypeTag](c: Context)(packageName: c.Expr[String]) = { 
    import c.universe._ 

    // Get package name from the expression tree 
    val Literal(Constant(name: String)) = packageName.tree 

    // Get all classes under given package name 
    val pkg = c.mirror.staticPackage(name) 

    // Obtain type symbols for the classes - implementation omitted 
    val types = getTypeSymbols(c.universe)(List(pkg)) 

    // Apply method for List. For easy readability in later applications 
    val listApply = Select(reify(List).tree, newTermName("apply")) 

    val result = types.map { 
    t => 
     val typeName = c.Expr[TypeSymbol](Ident(t)) 
     println(s"Typename: $typeName, $t, ${t.toType}") 

     reify(typeName.splice).tree 
    } 

    println(s"RESULT: ${showRaw(result)}") 

    c.Expr[List[reflect.runtime.universe.TypeSymbol]](Apply(listApply, result.toList)) 
} 

最初printlnプリント:

Typename: Expr[c.universe.TypeSymbol](Bar), class Bar, foo.Bar 
Typename: Expr[c.universe.TypeSymbol](Baz), class Baz, foo.Baz 

秒1枚の版画:

RESULT: List(Ident(foo.Bar), Ident(foo.Baz)) 

しかし、私は、このエラーメッセージが出ます:私はするために何をすべきか

[error] no type parameters for method any2ArrowAssoc: (x: A)ArrowAssoc[A] exist so that it can be applied to arguments (<notype>) 
[error] --- because --- 
[error] argument expression's type is not compatible with formal parameter type; 
[error] found : <notype> 
[error] required: ?A 
[error] Note that <none> extends Any, not AnyRef. 
[error] Such types can participate in value classes, but instances 
[error] cannot appear in singleton types or in reference comparisons. 

をこの作品を作る?私はIdentの代わりに別の何かを書かなければならないと思うが、何が分からないのか分からない。

Scala 2.10.2の使用。

ありがとうございます!

答えて

7

あなたはランタイム宇宙に反射成果物を作成するためにreifyTypeを使用する必要があります。

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

object PackageMacros { 
    def allTypeSymbols[T](packageName: String) = macro allTypeSymbols_impl[T] 

    def allTypeSymbols_impl[T: c.WeakTypeTag](c: Context)(
    packageName: c.Expr[String] 
) = { 
    import c.universe._ 

    val pkg = packageName.tree match { 
     case Literal(Constant(name: String)) => c.mirror.staticPackage(name) 
    } 

    val types = pkg.typeSignature.members.collect { 
     case sym: ClassSymbol => 
     c.reifyType(treeBuild.mkRuntimeUniverseRef, EmptyTree, sym.toType) 
    }.toList 

    val listApply = Select(reify(List).tree, newTermName("apply")) 

    c.Expr[List[Any]](Apply(listApply, types)) 
    } 
} 

のいずれかのように、これはあなたのタイプのタグではなく、シンボルのリストが表示されますが、あなたはかなり簡単にシンボルを得ることができます:

scala> PackageMacros.allTypeSymbols("foo").map(_.tpe.typeSymbol) foreach println 
class Baz$ 
class Bar 
class Baz 
trait FooTrait 
class Bar$ 

またはマクロ自体です。

+0

もう一度ありがとうTravis!マクロの 'TypeSymbol'sに変換しました。私はケースクラスで宣言された 'val'フィールドの' Map'をシンボルから外しましたが、アクセスしようとしている間にこのエラーが発生しました:http://pastebin.com/8dHDRMYy あなたのように 'Any'のために行きますか? また、私はMethodSymbolsのためにこれをどうしますか?方法はありますか? – Emre

関連する問題