2012-05-02 6 views
4

私はScalaのコンパイラプラグインを書いているし、「適用(単位:CompilationUnit」書き込みのポイントになってきていました。。メソッドをそのメソッド内の構文は、しかし、私を超えている次のコードは、http://www.scala-lang.org/node/140コンパイラプラグインからScalaプログラムのステートメントを見つける方法はありますか?

for (tree @ Apply(Select(rcvr, nme.DIV), List(Literal(Constant(0)))) <- unit.body; 
     if rcvr.tpe <:< definitions.IntClass.tpe) { 
     unit.error(tree.pos, "definitely division by zero") 
     } 
からです

この式はゼロで、すべての部門を見つけ、私はすべての実行文(TermTreesを??)見つけることが似た何かをする方法を見つけ出すことはできません

答えて

7

[OK]を、以下のファイルTwoStatements.scala仮定:。。

class TwoStatements { 
    def f { 
    println("first statement") 
    println("second statement") 
    } 
} 
を210

は、これらのコマンドを試してみてください。typerは、それが出力の対象となる後の位相ある

scalac -Yshow-trees -Xprint:typer TwoStatements.scala 
scalac -Yshow-trees-compact -Xprint:typer TwoStatements.scala 
scalac -Yshow-trees-stringified -Xprint:typer TwoStatements.scala 
scalac -Ybrowse:typer TwoStatements.scala 

注こと。したがって、自分のプラグインが実行されているフェーズに適したフェーズを選択してください。

-Yshow-trees-compactは、自分のコードで使用するものに正確に(またはかなり近い)出力を生成するものですが、読む。

他のものは読みやすく、独自のコードに翻訳するのは混乱するかもしれません。 -Yshow-trees-stringifiedは、ほとんどの情報を表示するので、-Yshow-treesより役立つでしょう。一方、-Ybrowse:typerはインタラクティブで、選択したツリーノードのコードを表示します。これは、特に大きなプログラムを見る場合に便利です。それでは、私は示唆していますが、あなたが処理したいコードが変換される方法を見ていることである

Apply(
    Select(
    Select(This(newTypeName("Test")), newTermName("five")), // assigned to rcvr 
    newTermName("$div")          // compared to nme.DIV 
    ), 
    List(Literal(Constant(0))))        // as is 
) 

:リンクされたブログの例で-Yshow-trees-compactをしようとした場合

、あなたはこのスニペットが表示されますプラグインが動作しているフェーズに入り、スニペットをつかんで、関心のない部分があればそれを変数に置き換えてください。

すべてDefDefには本文が6番目の要素として含まれています。複数のステートメントのListを持つBlockがあり、メソッド呼び出し(Apply)、ゲッター(Select)、アサイメント(Assign)、ifステートメント(If)などがあります。 ValDefのような他の種類の宣言にも、コードが関連付けられています。

tree @ Statement(...)のようなものをお探しの場合は存在しません。コードを表すものを識別するためにTermTree(より良い方法ではisTerm)を使用できますが、式の一部または完全なブロックから文を区別することはできません。

実際のコードのASTを見て、それがどのように機能するかを学んでください。a presentationを見て

EDIT

はちょうどscala/reflecti/api/Trees.scalaファイルの末尾にこのコメントに私をclued:あなたが仕事を示唆

// A standard pattern match 
    case EmptyTree => 
    case PackageDef(pid, stats) => 
    // package pid { stats } 
    case ClassDef(mods, name, tparams, impl) => 
    // mods class name [tparams] impl where impl = extends parents { defs } 
    case ModuleDef(mods, name, impl) =>        (eliminated by refcheck) 
    // mods object name impl where impl = extends parents { defs } 
    case ValDef(mods, name, tpt, rhs) => 
    // mods val name: tpt = rhs 
    // note missing type information is expressed by tpt = TypeTree() 
    case DefDef(mods, name, tparams, vparamss, tpt, rhs) => 
    // mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs 
    // note missing type information is expressed by tpt = TypeTree() 
    case TypeDef(mods, name, tparams, rhs) =>      (eliminated by erasure) 
    // mods type name[tparams] = rhs 
    // mods type name[tparams] >: lo <: hi, where lo, hi are in a TypeBoundsTree, 
               and DEFERRED is set in mods 
    case LabelDef(name, params, rhs) => 
    // used for tailcalls and like 
    // while/do are desugared to label defs as follows: 
    // while (cond) body ==> LabelDef($L, List(), if (cond) { body; L$() } else()) 
    // do body while (cond) ==> LabelDef($L, List(), body; if (cond) L$() else()) 
    case Import(expr, selectors) =>         (eliminated by typecheck) 
    // import expr.{selectors} 
    // Selectors are a list of pairs of names (from, to). 
    // The last (and maybe only name) may be a nme.WILDCARD 
    // for instance 
    // import qual.{x, y => z, _} would be represented as 
    // Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null))) 
    case Template(parents, self, body) => 
    // extends parents { self => body } 
    // if self is missing it is represented as emptyValDef 
    case Block(stats, expr) => 
    // { stats; expr } 
    case CaseDef(pat, guard, body) =>        (eliminated by transmatch/explicitouter) 
    // case pat if guard => body 
    case Alternative(trees) =>          (eliminated by transmatch/explicitouter) 
    // pat1 | ... | patn 
    case Star(elem) =>            (eliminated by transmatch/explicitouter) 
    // pat* 
    case Bind(name, body) =>          (eliminated by transmatch/explicitouter) 
    // name @ pat 
    case UnApply(fun: Tree, args)         (introduced by typer, eliminated by transmatch/explicitouter) 
    // used for unapply's 
    case ArrayValue(elemtpt, trees) =>        (introduced by uncurry) 
    // used to pass arguments to vararg arguments 
    // for instance, printf("%s%d", foo, 42) is translated to after uncurry to: 
    // Apply(
    // Ident("printf"), 
    // Literal("%s%d"), 
    // ArrayValue(<Any>, List(Ident("foo"), Literal(42)))) 
    case Function(vparams, body) =>         (eliminated by lambdaLift) 
    // vparams => body where vparams:List[ValDef] 
    case Assign(lhs, rhs) => 
    // lhs = rhs 
    case AssignOrNamedArg(lhs, rhs) =>        (eliminated by typer, resurrected by reifier) 
    // @annotation(lhs = rhs) 
    case If(cond, thenp, elsep) => 
    // if (cond) thenp else elsep 
    case Match(selector, cases) => 
    // selector match { cases } 
    case Return(expr) => 
    // return expr 
    case Try(block, catches, finalizer) => 
    // try block catch { catches } finally finalizer where catches: List[CaseDef] 
    case Throw(expr) => 
    // throw expr 
    case New(tpt) => 
    // new tpt always in the context: (new tpt).<init>[targs](args) 
    case Typed(expr, tpt) =>          (eliminated by erasure) 
    // expr: tpt 
    case TypeApply(fun, args) => 
    // fun[args] 
    case Apply(fun, args) => 
    // fun(args) 
    // for instance fun[targs](args) is expressed as Apply(TypeApply(fun, targs), args) 
    case ApplyDynamic(qual, args)         (introduced by erasure, eliminated by cleanup) 
    // fun(args) 
    case Super(qual, mix) => 
    // qual.super[mix]  qual is always This(something), if mix is empty, it is tpnme.EMPTY 
    case This(qual) => 
    // qual.this 
    case Select(qualifier, selector) => 
    // qualifier.selector 
    case Ident(name) => 
    // name 
    // note: type checker converts idents that refer to enclosing fields or methods 
    // to selects; name ==> this.name 
    case ReferenceToBoxed(ident) =>         (created by typer, eliminated by lambdalift) 
    // synthetic node emitted by macros to reference capture vars directly without going through ``elem'' 
    // var x = ...; fun { x } will emit Ident(x), which gets transformed to Select(Ident(x), "elem") 
    // if ReferenceToBoxed were used instead of Ident, no transformation would be performed 
    case Literal(value) => 
    // value 
    case TypeTree() =>            (introduced by refcheck) 
    // a type that's not written out, but given in the tpe attribute 
    case Annotated(annot, arg) =>         (eliminated by typer) 
    // arg @annot for types, arg: @annot for exprs 
    case SingletonTypeTree(ref) =>         (eliminated by uncurry) 
    // ref.type 
    case SelectFromTypeTree(qualifier, selector) =>     (eliminated by uncurry) 
    // qualifier # selector, a path-dependent type p.T is expressed as p.type # T 
    case CompoundTypeTree(templ: Template) =>      (eliminated by uncurry) 
    // parent1 with ... with parentN { refinement } 
    case AppliedTypeTree(tpt, args) =>        (eliminated by uncurry) 
    // tpt[args] 
    case TypeBoundsTree(lo, hi) =>         (eliminated by uncurry) 
    // >: lo <: hi 
    case ExistentialTypeTree(tpt, whereClauses) =>     (eliminated by uncurry) 
    // tpt forSome { whereClauses } 
+0

コマンドが、私はにScalaのコードを探していますCompilationUnitツリーからステートメントを取得できるコンパイラプラグインを入れてください。ありがとう。 –

+0

@BrianTarbox "ステートメント"を定義し、その定義をScala仕様の観点から行います。それ以外は正確な答えを与えることができます。そうしないと、実際のコードを検索し、取得したいものがどのように表現されているかを特定する必要があります。 –

+0

@BrianTarbox別のプレゼンテーションで見たことだけを追加しました。それは完全なパターンマッチのように見えるでしょう。 –

関連する問題