32.2. "ast" --- 抽象構文木
**************************

バージョン 2.5 で追加: 低級モジュール "_ast" はノードクラスだけを含み
ます。

バージョン 2.6 で追加: 高級モジュール "ast" は全てのヘルパーを含みます
。

**ソースコード:** Lib/ast.py

======================================================================

"ast" モジュールは、Python アプリケーションで Python の抽象構文木を処
理しやすくするものです。抽象構文そのものは、Python のリリースごとに変
化する可能性があります。このモジュールを使用すると、現在の文法をプログ
ラム上で知る助けになるでしょう。

抽象構文木を作成するには、 "ast.PyCF_ONLY_AST" を組み込み関数
"compile()" のフラグとして渡すか、あるいはこのモジュールで提供されてい
るヘルパー関数 "parse()" を使います。その結果は、 "ast.AST" を継承した
クラスのオブジェクトのツリーとなります。抽象構文木は組み込み関数
"compile()" を使って Python コード・オブジェクトにコンパイルすることが
できます。


32.2.1. Node クラス
===================

class ast.AST

   このクラスは全ての AST ノード・クラスの基底です。実際のノード・クラ
   スは 後ほど 示す "Parser/Python.asdl" ファイルから派生したものです
   。これらのクラスは "_ast" C モジュールで定義され、 "ast" にもエクス
   ポートし直されています。

   抽象文法の左辺のシンボル一つずつにそれぞれ一つのクラスがあります (
   たとえば "ast.stmt" や "ast.expr")。それに加えて、右辺のコンストラ
   クタ一つずつにそれぞれ一つのクラスがあり、これらのクラスは左辺のツ
   リーのクラスを継承しています。たとえば、 "ast.BinOp" は "ast.expr"
   から継承しています。代替を伴った生成規則 (production rules with
   alternatives) (別名 "sums") の場合、左辺は抽象クラスとなり、特定の
   コンストラクタ・ノードのインスタンスのみが作成されます。

   _fields

      各具象クラスは属性 "_fields" を持っており、すべての子ノードの名
      前をそこに保持しています。

      具象クラスのインスタンスは、各子ノードに対してそれぞれひとつの属
      性を持っています。この属性は、文法で定義された型となります。たと
      えば "ast.BinOp" のインスタンスは "left" という属性を持っており
      、その型は "ast.expr" です。

      これらの属性が、文法上 (クエスチョンマークを用いて) オプションで
      あるとマークされている場合は、その値が "None" となることもありま
      す。属性が0個以上の複数の値をとりうる場合 (アスタリスクでマーク
      されている場合) は、値は Python のリストで表されます。全ての属性
      は AST を "compile()" でコンパイルする際には存在しなければならず
      、そして妥当な値でなければなりません。

   lineno
   col_offset

      "ast.expr" や "ast.stmt" のサブクラスのインスタンスにはさらに
      "lineno" や "col_offset" といった属性があります。 "lineno" はソ
      ーステキスト上の行番号 (1 から数え始めるので、最初の行の行番号は
      1 となります)、そして "col_offset" はノードが生成した最初のトー
      クンの UTF-8 バイトオフセットとなります。 UTF-8 オフセットが記録
      される理由は、パーサが内部で UTF-8 を使用するからです。

   クラス "ast.T" のコンストラクタは引数を次のように解析します:

   * 位置による引数があるとすれば、 "T._fields" にあるのと同じだけの
     個 数が無ければなりません。これらの引数はそこにある名前を持った属
     性 として割り当てられます。

   * キーワード引数があるとすれば、それらはその名前の属性にその値を
     割 り当てられます。

   たとえば、 "ast.UnaryOp" ノードを生成して属性を埋めるには、次のよう
   にすることができます

      node = ast.UnaryOp()
      node.op = ast.USub()
      node.operand = ast.Num()
      node.operand.n = 5
      node.operand.lineno = 0
      node.operand.col_offset = 0
      node.lineno = 0
      node.col_offset = 0

   もしくはよりコンパクトにも書けます

      node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0),
                         lineno=0, col_offset=0)

   バージョン 2.6 で追加: 上で説明したコンストラクタが付け加えられまし
   た。Python 2.5 においてはノードは引数なしのコンストラクタを呼び出し
   て生成した後、全ての属性をセットしていかなければなりませんでした。


32.2.2. 抽象文法 (Abstract Grammar)
===================================

このモジュールでは文字列定数 "__version__" を定義しています。これは、
以下に示すファイルの 10 進の Subversion リビジョン番号です。

抽象文法は、現在次のように定義されています:

   -- ASDL's five builtin types are identifier, int, string, object, bool

   module Python version "$Revision$"
   {
   	mod = Module(stmt* body)
   	    | Interactive(stmt* body)
   	    | Expression(expr body)

   	    -- not really an actual node but useful in Jython's typesystem.
   	    | Suite(stmt* body)

   	stmt = FunctionDef(identifier name, arguments args, 
                               stmt* body, expr* decorator_list)
   	      | ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)
   	      | Return(expr? value)

   	      | Delete(expr* targets)
   	      | Assign(expr* targets, expr value)
   	      | AugAssign(expr target, operator op, expr value)

   	      -- not sure if bool is allowed, can always use int
    	      | Print(expr? dest, expr* values, bool nl)

   	      -- use 'orelse' because else is a keyword in target languages
   	      | For(expr target, expr iter, stmt* body, stmt* orelse)
   	      | While(expr test, stmt* body, stmt* orelse)
   	      | If(expr test, stmt* body, stmt* orelse)
   	      | With(expr context_expr, expr? optional_vars, stmt* body)

   	      -- 'type' is a bad name
   	      | Raise(expr? type, expr? inst, expr? tback)
   	      | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
   	      | TryFinally(stmt* body, stmt* finalbody)
   	      | Assert(expr test, expr? msg)

   	      | Import(alias* names)
   	      | ImportFrom(identifier? module, alias* names, int? level)

   	      -- Doesn't capture requirement that locals must be
   	      -- defined if globals is
   	      -- still supports use as a function!
   	      | Exec(expr body, expr? globals, expr? locals)

   	      | Global(identifier* names)
   	      | Expr(expr value)
   	      | Pass | Break | Continue

   	      -- XXX Jython will be different
   	      -- col_offset is the byte offset in the utf8 string the parser uses
   	      attributes (int lineno, int col_offset)

   	      -- BoolOp() can use left & right?
   	expr = BoolOp(boolop op, expr* values)
   	     | BinOp(expr left, operator op, expr right)
   	     | UnaryOp(unaryop op, expr operand)
   	     | Lambda(arguments args, expr body)
   	     | IfExp(expr test, expr body, expr orelse)
   	     | Dict(expr* keys, expr* values)
   	     | Set(expr* elts)
   	     | ListComp(expr elt, comprehension* generators)
   	     | SetComp(expr elt, comprehension* generators)
   	     | DictComp(expr key, expr value, comprehension* generators)
   	     | GeneratorExp(expr elt, comprehension* generators)
   	     -- the grammar constrains where yield expressions can occur
   	     | Yield(expr? value)
   	     -- need sequences for compare to distinguish between
   	     -- x < 4 < 3 and (x < 4) < 3
   	     | Compare(expr left, cmpop* ops, expr* comparators)
   	     | Call(expr func, expr* args, keyword* keywords,
   			 expr? starargs, expr? kwargs)
   	     | Repr(expr value)
   	     | Num(object n) -- a number as a PyObject.
   	     | Str(string s) -- need to specify raw, unicode, etc?
   	     -- other literals? bools?

   	     -- the following expression can appear in assignment context
   	     | Attribute(expr value, identifier attr, expr_context ctx)
   	     | Subscript(expr value, slice slice, expr_context ctx)
   	     | Name(identifier id, expr_context ctx)
   	     | List(expr* elts, expr_context ctx) 
   	     | Tuple(expr* elts, expr_context ctx)

   	      -- col_offset is the byte offset in the utf8 string the parser uses
   	      attributes (int lineno, int col_offset)

   	expr_context = Load | Store | Del | AugLoad | AugStore | Param

   	slice = Ellipsis | Slice(expr? lower, expr? upper, expr? step) 
   	      | ExtSlice(slice* dims) 
   	      | Index(expr value) 

   	boolop = And | Or 

   	operator = Add | Sub | Mult | Div | Mod | Pow | LShift 
                    | RShift | BitOr | BitXor | BitAnd | FloorDiv

   	unaryop = Invert | Not | UAdd | USub

   	cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn

   	comprehension = (expr target, expr iter, expr* ifs)

   	-- not sure what to call the first argument for raise and except
   	excepthandler = ExceptHandler(expr? type, expr? name, stmt* body)
   	                attributes (int lineno, int col_offset)

   	arguments = (expr* args, identifier? vararg, 
   		     identifier? kwarg, expr* defaults)

           -- keyword arguments supplied to call
           keyword = (identifier arg, expr value)

           -- import name with optional 'as' alias.
           alias = (identifier name, identifier? asname)
   }


32.2.3. "ast" ヘルパー
======================

バージョン 2.6 で追加.

ノード・クラスの他に、 "ast" モジュールは以下のような抽象構文木をトラ
バースするためのユーティリティ関数やクラスも定義しています:

ast.parse(source, filename='<unknown>', mode='exec')

   *source* を解析して AST ノードにします。"compile(source, filename,
   mode, ast.PyCF_ONLY_AST)" と等価です。

ast.literal_eval(node_or_string)

   式ノード、または Python の式を表す Unicode または *Latin-1* エンコ
   ード文字列、コンテナのディスプレイ表現を表す文字列、を安全に評価し
   ます。与えられる文字列またはノードは次のリテラルのみからなるものに
   限られます: 文字列, 数, タプル, リスト, 辞書, ブール値, "None" 。

   この関数は Python の式を含んだ信頼出来ない出どころからの文字列を、
   値自身を解析することなしに安全に評価するのに使えます。この関数は、
   例えば演算や添え字を含んだ任意の複雑な表現を評価するのには使えませ
   ん。

ast.get_docstring(node, clean=True)

   与えられた *node* (これは "FunctionDef", "ClassDef", "Module" のい
   ずれかのノードでなければなりません) のドキュメント文字列を返します
   。もしドキュメント文字列が無ければ "None" を返します。 *clean* が真
   ならば、ドキュメント文字列のインデントを "inspect.cleandoc()" を用
   いて一掃します。

ast.fix_missing_locations(node)

   "compile()" はノード・ツリーをコンパイルする際、 "lineno" と
   "col_offset" 両属性をサポートする全てのノードに対しそれが存在するも
   のと想定します。生成されたノードに対しこれらを埋めて回るのはどちら
   かというと退屈な作業なので、このヘルパーが再帰的に二つの属性がセッ
   トされていないものに親ノードと同じ値をセットしていきます。再帰の出
   発点が *node* です。

ast.increment_lineno(node, n=1)

   *node* から始まるツリーの全てのノードの行番号を *n* ずつ増やします
   。これはファイルの中で別の場所に「コードを動かす」ときに便利です。

ast.copy_location(new_node, old_node)

   ソースの場所 ("lineno" と "col_offset") を *old_node* から
   *new_node* に可能ならばコピーし、 *new_node* を返します。

ast.iter_fields(node)

   *node* にある "node._fields" のそれぞれのフィールドを "(フィールド
   名, 値)" のタプルとして yield します。

ast.iter_child_nodes(node)

   *node* の直接の子ノード全てを yield します。すなわち、yield される
   のは、ノードであるような全てのフィールドおよびノードのリストである
   ようなフィールドの全てのアイテムです。

ast.walk(node)

   *node* の全ての子孫ノード(*node* 自体を含む)を再帰的に yield します
   。順番は決められていません。この関数はノードをその場で変更するだけ
   で文脈を気にしないような場合に便利です。

class ast.NodeVisitor

   抽象構文木を渡り歩いてビジター関数を見つけたノードごとに呼び出すノ
   ード・ビジターの基底クラスです。この関数は "visit()" メソッドに送ら
   れる値を返してもかまいません。

   このクラスはビジター・メソッドを付け加えたサブクラスを派生させるこ
   とを意図しています。

   visit(node)

      ノードを訪れます。デフォルトの実装では "self.visit_*classname*"
      というメソッド (ここで *classname* はノードのクラス名です) を呼
      び出すか、そのメソッドがなければ "generic_visit()" を呼び出しま
      す。

   generic_visit(node)

      このビジターはノードの全ての子について "visit()" を呼び出します
      。

      注意して欲しいのは、専用のビジター・メソッドを具えたノードの子ノ
      ードは、このビジターが "generic_visit()" を呼び出すかそれ自身で
      子ノードを訪れない限り訪れられないということです。

   トラバースの途中でノードを変化させたいならば "NodeVisitor" を使って
   はいけません。そうした目的のために変更を許す特別なビジター
   ("NodeTransformer") があります。

class ast.NodeTransformer

   "NodeVisitor" のサブクラスで抽象構文木を渡り歩きながらノードを変更
   することを許すものです。

   "NodeTransformer" は抽象構文木(AST)を渡り歩き、ビジター・メソッドの
   戻り値を使って古いノードを置き換えたり削除したりします。ビジター・
   メソッドの戻り値が "None" ならば、ノードはその場から取り去られ、そ
   うでなければ戻り値で置き換えられます。置き換えない場合は戻り値が元
   のノードそのものであってもかまいません。

   それでは例を示しましょう。Name (たとえば "foo") を見つけるたび全て
   "data['foo']" に書き換える変換器 (transformer) です:

      class RewriteName(NodeTransformer):

          def visit_Name(self, node):
              return copy_location(Subscript(
                  value=Name(id='data', ctx=Load()),
                  slice=Index(value=Str(s=node.id)),
                  ctx=node.ctx
              ), node)

   操作しようとしているノードが子ノードを持つならば、その子ノードの変
   形も自分で行うか、またはそのノードに対し最初に "generic_visit()" メ
   ソッドを呼び出すか、それを行うのはあなたの責任だということを肝に銘
   じましょう。

   文のコレクションであるようなノード (全ての文のノードが当てはまりま
   す) に対して、このビジターは単独のノードではなくノードのリストを返
   すかもしれません。

   たいてい、変換器の使い方は次のようになります:

      node = YourTransformer().visit(node)

ast.dump(node, annotate_fields=True, include_attributes=False)

   *node* 中のツリーのフォーマットされたダンプを返します。主な使い道は
   デバッグです。返される文字列は名前とフィールドの値を表示します。こ
   れを使うとコードは評価できなくなりますので、評価が必要ならば
   *annotate_fields* に "False" をセットしなければなりません。行番号や
   列オフセットのような属性はデフォルトではダンプされません。これが欲
   しければ、*include_attributes* を "True" にセットすることができます
   。
