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

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

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

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

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


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
   end_lineno
   end_col_offset

      Instances of "ast.expr" and "ast.stmt" subclasses have "lineno",
      "col_offset", "lineno", and "col_offset" attributes.  The
      "lineno" and "end_lineno" are the first and last line numbers of
      source text span (1-indexed so the first line is line 1) and the
      "col_offset" and "end_col_offset" are the corresponding UTF-8
      byte offsets of the first and last tokens that generated the
      node. The UTF-8 offset is recorded because the parser uses UTF-8
      internally.

      コンパイラは終了位置を必要としないことに注意してください。このた
      め終了位置は省略可能です。終了位置を示すオフセットは最後のシンボ
      ルの *後の位置* になります。例えば一行で書かれた式のソースコード
      のセグメントは "source_line[node.col_offset :
      node.end_col_offset]" により取得できます。

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

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

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

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

      node = ast.UnaryOp()
      node.op = ast.USub()
      node.operand = ast.Constant()
      node.operand.value = 5
      node.operand.lineno = 0
      node.operand.col_offset = 0
      node.lineno = 0
      node.col_offset = 0

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

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

バージョン 3.8 で変更: "ast.Constant" が全ての定数に使われるようになり
ました。

バージョン 3.8 で非推奨: "ast.Num"、 "ast.Str"、"ast.Bytes"、
"ast.NameConstant" そして "ast.Ellipsis" は現バージョンまで使用可能で
すが、将来のPythonリリースで削除される予定です。削除されるまでの間、こ
れらをインスタンス化すると、異なるクラスのインスタンスが返されます。


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

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

   -- ASDL's 5 builtin types are:
   -- identifier, int, string, object, constant

   module Python
   {
       mod = Module(stmt* body, type_ignore *type_ignores)
           | Interactive(stmt* body)
           | Expression(expr body)
           | FunctionType(expr* argtypes, expr returns)

           -- 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, expr? returns,
                          string? type_comment)
             | AsyncFunctionDef(identifier name, arguments args,
                                stmt* body, expr* decorator_list, expr? returns,
                                string? type_comment)

             | ClassDef(identifier name,
                expr* bases,
                keyword* keywords,
                stmt* body,
                expr* decorator_list)
             | Return(expr? value)

             | Delete(expr* targets)
             | Assign(expr* targets, expr value, string? type_comment)
             | AugAssign(expr target, operator op, expr value)
             -- 'simple' indicates that we annotate simple name without parens
             | AnnAssign(expr target, expr annotation, expr? value, int simple)

             -- use 'orelse' because else is a keyword in target languages
             | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
             | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
             | While(expr test, stmt* body, stmt* orelse)
             | If(expr test, stmt* body, stmt* orelse)
             | With(withitem* items, stmt* body, string? type_comment)
             | AsyncWith(withitem* items, stmt* body, string? type_comment)

             | Raise(expr? exc, expr? cause)
             | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
             | Assert(expr test, expr? msg)

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

             | Global(identifier* names)
             | Nonlocal(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, int? end_lineno, int? end_col_offset)

             -- BoolOp() can use left & right?
       expr = BoolOp(boolop op, expr* values)
            | NamedExpr(expr target, expr value)
            | 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
            | Await(expr value)
            | Yield(expr? value)
            | YieldFrom(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)
            | FormattedValue(expr value, int? conversion, expr? format_spec)
            | JoinedStr(expr* values)
            | Constant(constant value, string? kind)

            -- the following expression can appear in assignment context
            | Attribute(expr value, identifier attr, expr_context ctx)
            | Subscript(expr value, slice slice, expr_context ctx)
            | Starred(expr value, 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, int? end_lineno, int? end_col_offset)

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

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

       boolop = And | Or

       operator = Add | Sub | Mult | MatMult | 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, int is_async)

       excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
                       attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

       arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs,
                    expr* kw_defaults, arg? kwarg, expr* defaults)

       arg = (identifier arg, expr? annotation, string? type_comment)
              attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

       -- keyword arguments supplied to call (NULL identifier for **kwargs)
       keyword = (identifier? arg, expr value)

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

       withitem = (expr context_expr, expr? optional_vars)

       type_ignore = TypeIgnore(int lineno, string tag)
   }


"ast" ヘルパー
==============

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

ast.parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None)

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

   "type_comments=True" が与えられると、パーサは **PEP 484** および
   **PEP 526** で規定された型コメントをチェックし、返すように修正され
   ます。これは "ast.PyCF_TYPE_COMMENTS" を追加したフラグを
   "compile()" に渡すことと等価です。パーサは不適切な場所に配置された
   型コメントに対してシンタックスエラーをレポートします。 このフラグが
   ない場合、型コメントは無視されて AST ノードの "type_comment" フィー
   ルドは常に "None" になります。さらに、 "# type: ignore" コメントの
   位置は "Module" の "type_ignores" 属性として返されます (それ以外の
   場合は常に空のリストになります)。

   さらに "mode" が "'func_type'" の場合、入力構文は、たとえば "(str,
   int) -> List[str]" のような **PEP 484** の "シグネチャ型コメント
   (signature type comments)" に対応するように修正されます。

   また、 "feature_version" を "(major, minor)" のタプルに設定すると、
   パーサは指定された Python バージョンの文法で構文解析を試みます。今
   のところ "major" は "3" でなければなりません。たとえば、
   "feature_version=(3, 4)" と設定すると "async" と "await" を変数名と
   して使うことが可能になります。 サポートされている最低のバージョンは
   "(3, 4)"; 最高のバージョンは "sys.version_info[0:2]" です。

   警告:

     十分に大きい文字列や複雑な文字列によって Python の抽象構文木コン
     パイラのスタックの深さの限界を越えることで、 Python インタプリタ
     をクラッシュさせることができます。

   バージョン 3.8 で変更: "type_comments"、"mode='func_type'"、
   >>``<<feature_version``が追加されました。

ast.literal_eval(node_or_string)

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

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

   警告:

     十分に大きい文字列や複雑な文字列によって Python の抽象構文木コン
     パイラのスタックの深さの限界を越えることで、 Python インタプリタ
     をクラッシュさせることができます。

   バージョン 3.2 で変更: バイト列リテラルと集合リテラルが受け取れるよ
   うになりました。

ast.get_docstring(node, clean=True)

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

   バージョン 3.5 で変更: "AsyncFunctionDef" がサポートされました。

ast.get_source_segment(source, node, *, padded=False)

   *source* のうちで *node* を生成したソースコードのセグメントを取得し
   ます。位置情報  ("lineno", "end_lineno", "col_offset", または
   "end_col_offset") が欠けている場合 "None" を返します。

   *padded* が "True" の場合、複数行にわたる文の最初の行が元の位置に一
   致するように空白文字でパディングされます。

   バージョン 3.8 で追加.

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", "end_lineno", および
   "end_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") があります。

   バージョン 3.8 で非推奨: "visit_Num()", "visit_Str()",
   "visit_Bytes()", "visit_NameConstant()" および "visit_Ellipsis()"
   の各メソッドは非推奨です。また将来の Python バージョンでは呼び出さ
   れなくなります。全ての定数ノードを扱うには "visit_Constant()" を追
   加してください。

class ast.NodeTransformer

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

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

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

      class RewriteName(NodeTransformer):

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

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

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

   "NodeTransformer" が(たとえば、 "lineno" のような)位置情報を与えず
   に(元の木の一部ではなく)新しいノードを導入する場合、
   "fix_missing_locations()" を新しいサブツリーで呼び出して、位置情報
   を再計算する必要があります。

      tree = ast.parse('foo', mode='eval')
      new_tree = fix_missing_locations(RewriteName().visit(tree))

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

      node = YourTransformer().visit(node)

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

   *node* 内のツリーのフォーマットされたダンプを返します。主な使い道は
   デバッグです。 *annotate_fields* が(デフォルトで)trueの場合、返され
   る文字列はフィールドの名前と値を示します。 *annotate_fields* が
   falseの場合、あいまいさのないフィールド名を省略することにより、結果
   文字列はよりコンパクトになります。行番号や列オフセットのような属性
   はデフォルトではダンプされません。これがほ欲しければ、
   *include_attributes* をtrueにセットすることができます。

参考:

  外部ドキュメント Green Tree Snakes には Python AST についての詳細が
  書かれています。

  ASTTokens は Python AST を、生成元のソースコードのトークン位置やテキ
  ストで注解します。これはソースコード変換を行うツールで有用です。

  leoAst.py unifies the token-based and parse-tree-based views of
  python programs by inserting two-way links between tokens and ast
  nodes.

  LibCST はコードを ast ツリーに似た構文木 (Concrete Syntax Tree) にパ
  ースし、かつ全ての書式設定の詳細を保持します。これは自動リファクタリ
  ングアプリケーション (codemod) やリンタを作成する際に有用です。

  Parso はエラーリカバリや異なる Python バージョン (複数の Python バー
  ジョン) での復元可能なパース (round-trip parsing) をサポートします。
  また、 Parso は Python ファイル内の複数の文法エラーをリストすること
  もできます。
