2011-10-17 7 views
35

Scala Compiler Pluginでは、既存の特性を実装する新しいクラスを作成しようとしています。これまでのところ、私のコードは次のようになります:Scala Compiler Pluginに新しいクラスを追加するには?

def trait2Impl(original: ClassDef, newName: String): ClassDef = { 
    val impl = original.impl 
    // Seems OK to have same self, but does not make sense to me ... 
    val self = impl.self 
    // TODO: implement methods ... 
    val body = impl.body 
    // We implement original 
    val parents = original :: impl.parents 
    val newImpl = treeCopy.Template(impl, parents, self, body) 
    val name = newTypeName(newName) 
    // We are a syntheic class, not a user-defined trait 
    val mods = (original.mods | SYNTHETIC) &~ TRAIT 
    val tp = original.tparams 
    val result = treeCopy.ClassDef(original, mods, name, tp, newImpl) 
    // Same Package? 
    val owner = original.symbol.owner 
    // New symbol. What's a Position good for? 
    val symbol = new TypeSymbol(owner, NoPosition, name) 
    result.setSymbol(symbol) 
    symbol.setFlag(SYNTHETIC) 
    symbol.setFlag(ABSTRACT) 
    symbol.resetFlag(INTERFACE) 
    symbol.resetFlag(TRAIT) 
    owner.info.decls.enter(symbol) 
    result 
} 

しかし、パッケージには追加されません。私はそれが実際にパッケージが生成を引き起こす特性の前に "横断"されたか、TypingTransformerの "def def transform(tree:Tree):Tree"メソッドがという1つしか返さないためであると思われます Tree、for受け取ったすべてのツリー。新しいツリーを実際に作成することはできませんが、変更するのは1つだけです。

既存のパッケージに新しいクラスを追加するにはどうすればよいですか?もし私が "transform(Tree)"を取得したときにパッケージを変換すると動作するかもしれませんが、パッケージの内容はまだ分かりませんので、新しいClassを生成することはできません。 。あるいは、Symbolの "Position"パラメータに関連しているかもしれませんか?

これまでのところ、ツリーが変更されていても、コンパイラプラグインで完全に新しいクラスが作成された例はありませんでした。

+0

に変換しているのですか?私は似たようなものを持っているので、私は不思議に思っていました...私はあなたの形質の親にマッチする必要があると思います。つまり、PackageDefとTemplateを調べて、あなたの体のすべての特徴を見つけ出します。その後、変換されたPackageDefとTemplateを返すことができます –

+0

はい、Scalaメーリングリストの助けを借りています。しかし、私はクラスを*同じパッケージにしか作成できないので、まだそこにはいません。物事を整理したら自分の質問に答えを投稿しようとします。 –

+0

あなたの質問に今すぐお答えください!私は同じ質問があるので(https://github.com/iron9light/autoguice) – iron9light

答えて

2

完全なソースコードはここにある:https://gist.github.com/1794246

トリックは、新しく作成されたClassDef Sを保存し、新しいPackageDefを作成するときにそれらを使用することです。シンボルとツリーの両方を処理する必要があることに注意してください。パッケージシンボルは単なるハンドルです。コードを生成するには、ASTを生成する必要があります(クラスの場合と同様に、シンボルにクラス名と型が含まれていますが、コードはClassDefツリーにあります)。

あなたが指摘したように、パッケージ定義はクラスよりもツリーの上にあるので、最初に再帰する必要があります(既存のクラスから新しいクラスを生成すると仮定します)。次に、サブツリーが一度トラバースされると、新しいクラスを持つ新しいPackageDef(すべてのコンパイル単位にはパッケージ定義があり、デフォルトでは空のパッケージです)を準備することができます。ソースコードを想定した例で

は、

class Foo { 
    def foo { 
    "spring" 
    } 
} 

コンパイラは

package <empty> { 
    class Foo { 
    def foo { 
     "spring" 
    } 
    } 
} 

にそれをラップし、プラグインは、あなたが問題を解決しました

package <empty> { 
    class Foo { 
    def foo { 
     "spring" 
    } 
    } 
    package mypackage { 
    class MyClass extends AnyRef 
    } 
} 
+0

ありがとうございました!私はそれを試しましたが、あなたが "熟達者"の一人であるので、あなたはそれを正しく持っていなければなりません。これを追加したいと思います。これは特にあなたとは関係がありません。私は数か月でScalaを使用しませんでした。そして、Scalaコミュニティは、このような基本的な質問(これは、Scalaコミュニティが非友好的/非有用/ Javaコンパイラのプラグインで耳障りなことになる人)は、*誰かが賞品を受け取ったときに*ヶ月*後にしか答えられない "*。私はScala言語のメーリングリストに尋ねた。 –

+2

私はあなたの意見を理解していますが、この質問に基づいてScalaコミュニティーを判断してはいけません。ほとんどのScala質問は、質の高い、迅速な回答を得ていますが、これは間違いなく 'それはコンパイラを使って答えを知っている人が必要です(Scalaチームのほとんどの人がSOVを頻繁に読んでいない)、それはスカラックが決してしないものなので、例を見つけることは不可能です。解決策は短いものの、すべてを得るには1時間ほどかかりました正しく動作しています。 –

+0

もう一度ありがとう!まもなく言いたいことは、誰かが「Javaの質問」を持っていると、ここや他の場所に質問することができます。答えが見つかったら、Scalaの質問には答えられません。 Scalaのメーリングリストであれば、それはあなた自身であり、それは本当にうつ病です。私は誰かが "ハードコアScala"本を書くことを望む。 「Scala in Depth」はまだ完成しておらず、約200ページになると、すべての表面を「ハードなもの」に傷つけるだけです。しかし、ハードなものはJavaよりもはるかに難しく、潜在的なバイヤーは十分ではありません。 –

関連する問題