2013-10-24 11 views
13

Iはtranformsコードのようなマクロがある場合:ランタイム反射ユニバースとマクロユニバースがscala.Noneの2つの異なるツリーを作成するのはなぜですか?

(src: a.b.c.TestEntity) => 
    { 
     z.y.TestTable(None) 
    } 

は、Iのような抽出器を使用することができ、そのASTのなし一部に一致するようにする:なし一部のshowRawとして

object NoneExtractor { 
    def unapply(t: Tree): Boolean = t match { 
     case Select(Ident(scala), none) if scala.encoded == "scala" && none.encoded == "None" => true 
     case _ => false 
    } 
    } 

ASTのようになっています

Select(Ident(scala), None) 

しかし、私はNoneExtractorのユニットテストを書きたい場合、私はしたくありませんマクロのコンパイルと再構築、およびマクロのコンパイル中のプロジェクトでのテストのホスト。私は、実行時の反射を示唆してマクロのプロジェクト内の抽出がして行く方法であるユニットテストしたい:

val t = reify { 

    (src: a.b.c.TestEntity) => 
    { 
     z.y.TestTable(None) 
    } 

}.tree 

しかし、木は全く異なるとなしのように見えないその木のshowRawである:

Ident(scala.None) 

これは、マイナステストを作成して、マクロのエラー処理をチェックするのに悪いニュースです。コードがコンパイルされず、コンパイルエラーでネガティブテストをデバッグすることができないため、別のプロジェクトのマクロを使用してマクロに対して否定的なテストを書くことはできません。

コンパイル時のリフレクションと実行時のリフレクションでは、何も全く同じように表現できないのはなぜですか?コンパイル時の反映中にマクロに渡されるのと同じASTであるマクロプロジェクト内にテスト可能なツリーフラグメントを作成する方法はありますか?

+0

ツリー表示に基づいて特定の値を選ぶことは、マクロの土地に完全に入っていても、ややこしいことです。代わりに 't.tpe =:= typeOf [None.type]'のようなことをすることができますか? –

+0

私は実際にネストされたマッチステートメントとASTを構造的にマッチさせる必要があります。私は機能的ではないので、if/then/else/callスタイルの命令コードから始めました。それは関数の一致/ case/match/case/....にリファクタリングしているので、コードの約5倍になりました。マクロ宇宙apiには膨大な量の抽出器が組み込まれています。だから私の理解エクストラクターとネストされた一致は、これを行うための標準的な方法です。私の質問は、どのように別のアプローチを完全に取るかという問題ではなく、標準的な方法をテストする方法です。 – simbo1905

答えて

0

この不一致を回避するには、パターン一致で今後quasiqoutesを使用してください。彼らはこのように離れAST抽象的で両方の表現で動作します(ASTは、コンパイラとにかく具体的である、Scalaは今のところ、単一のコンパイラ言語であるが、コンパイラの内部表現に依存するとても素敵ではありません):

case q"_root_.scala.None" => ... 

は両方のASTに一致します。また、表現を心配する必要がないように、q"_root_.scala.None"でツリーを作成することもできます。スカラ2.11でquasiquotesがリリースされたときReifyは廃止される予定です。 scala 2.10でquasiquotesを使用するには、macro paradiseを使用できます。

Here is a nice WIP guide on scala quasiquotes

関連する問題