"ast" --- Árvores de Sintaxe Abstrata
*************************************

**Código-fonte:** Lib/ast.py

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

O módulo "ast" ajuda os aplicativos Python a processar árvores da
gramática de sintaxe abstrata do Python. A sintaxe abstrata em si pode
mudar em cada lançamento do Python; este módulo ajuda a descobrir
programaticamente como é a gramática atual.

Uma árvore de sintaxe abstrata pode ser gerada passando
"ast.PyCF_ONLY_AST" como um sinalizador para a função interna
"compile()", ou usando o auxiliar "parse()" fornecido neste módulo. O
resultado será uma árvore de objetos cujas classes herdam de
"ast.AST". Uma árvore de sintaxe abstrata pode ser compilada em um
objeto de código Python usando a função interna "compile()".


Classes de nó
=============

class ast.AST

   Esta é a base de todas as classes de nós AST. As classes de nós
   reais são derivadas do arquivo "Parser/Python.asdl", o qual é
   reproduzido abaixo. Elas são definidas no módulo C "_ast" e
   reexportadas em "ast".

   Há uma classe definida para cada símbolo do lado esquerdo na
   gramática abstrata (por exemplo, "ast.stmt" ou "ast.expr"). Além
   disso, existe uma classe definida para cada construtor no lado
   direito; essas classes herdam das classes para as árvores do lado
   esquerdo. Por exemplo, "ast.BinOp" herda de "ast.expr". Para regras
   de produção com alternativas ("somas"), a classe do lado esquerdo é
   abstrata: apenas instâncias de nós construtores específicos são
   criadas.

   _fields

      Cada classe concreta possui um atributo "_fields" que fornece os
      nomes de todos os nós filhos.

      Cada instância de uma classe concreta tem um atributo para cada
      nó filho, do tipo definido na gramática. Por exemplo, as
      instâncias "ast.BinOp" possuem um atributo "left" do tipo
      "ast.expr".

      Se estes atributos estiverem marcados como opcionais na
      gramática (usando um ponto de interrogação), o valor pode ser
      "None". Se os atributos puderem ter valor zero ou mais (marcados
      com um asterisco), os valores serão representados como listas do
      Python. Todos os atributos possíveis devem estar presentes e ter
      valores válidos ao compilar uma AST com "compile()".

   lineno
   col_offset

      Instâncias das subclasses "ast.expr" e "ast.stmt" possuem
      atributos "lineno" e "col_offset". O "lineno" é o número da
      linha do texto fonte (indexado em 1, de modo que a primeira
      linha é a linha 1) e o "col_offset" é o deslocamento de bytes
      UTF-8 do primeiro token que gerou o nó. O deslocamento UTF-8 é
      registrado porque o analisador usa o UTF-8 internamente.

   O construtor de uma classe "ast.T" analisa seus argumentos da
   seguinte forma:

   * Se houver argumentos posicionais, deve haver tantos quanto houver
     itens em "T._fields"; eles serão atribuídos como atributos desses
     nomes.

   * Se houver argumentos de palavra-chave, eles definirão os
     atributos dos mesmos nomes para os valores fornecidos.

   Por exemplo, para criar e popular um nó "ast.UnaryOp", você poderia
   usar

      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

   ou a forma mais compacta

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


Gramática Abstrata
==================

A gramática abstrata está atualmente definida da seguinte forma:

   -- ASDL's 7 builtin types are:
   -- identifier, int, string, bytes, object, singleton, constant
   --
   -- singleton: None, True or False
   -- constant can be None, whereas None means "no value" for object.

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

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

             | Delete(expr* targets)
             | Assign(expr* targets, expr value)
             | 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)
             | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse)
             | While(expr test, stmt* body, stmt* orelse)
             | If(expr test, stmt* body, stmt* orelse)
             | With(withitem* items, stmt* body)
             | AsyncWith(withitem* items, stmt* body)

             | 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)

             -- 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
            | 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)
            | Num(object n) -- a number as a PyObject.
            | Str(string s) -- need to specify raw, unicode, etc?
            | FormattedValue(expr value, int? conversion, expr? format_spec)
            | JoinedStr(expr* values)
            | Bytes(bytes s)
            | NameConstant(singleton value)
            | Ellipsis
            | Constant(constant value)

            -- 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)

       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)

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

       arg = (identifier arg, expr? annotation)
              attributes (int lineno, int 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)
   }



Auxiliares de "ast"
===================

Além das classes de nós, o módulo "ast" define essas funções e classes
utilitárias para percorrer árvores de sintaxe abstrata:

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

   Analisa a fonte em um nó AST. Equivalente a "compile(source,
   filename, mode, ast.PyCF_ONLY_AST)".

   Aviso:

     É possível travar o interpretador Python com uma string
     suficientemente grande/complexa devido às limitações de
     profundidade da pilha no compilador de AST do Python.

ast.literal_eval(node_or_string)

   Avalia com segurança um nó de expressão ou uma string contendo um
   literal Python ou exibição de contêiner. A string ou o nó fornecido
   pode consistir apenas nas seguintes estruturas literais de Python:
   strings, bytes, números, tuplas, listas, dicts, conjuntos,
   booleanos e "None".

   Isso pode ser usado para avaliar com segurança strings contendo
   valores Python de fontes não confiáveis sem a necessidade de
   analisar os valores por si próprio. Não é capaz de avaliar
   expressões arbitrariamente complexas, por exemplo, envolvendo
   operadores ou indexação.

   Aviso:

     É possível travar o interpretador Python com uma string
     suficientemente grande/complexa devido às limitações de
     profundidade da pilha no compilador de AST do Python.

   Alterado na versão 3.2: Agora permite bytes e literais de
   conjuntos.

ast.get_docstring(node, clean=True)

   Retorna a docstring do *nó* dado (que deve ser um nó "FunctionDef",
   "AsyncFunctionDef", "ClassDef" ou "Module") ou "None" se não tiver
   uma docstring. Se *clean* for verdadeiro, limpa o recuo da
   docstring com "inspect.cleandoc()".

   Alterado na versão 3.5: Não há suporte a "AsyncFunctionDef".

ast.fix_missing_locations(node)

   Quando você compila uma árvore de nós com "compile()", o compilador
   espera atributos :attr:` lineno` e "col_offset" para cada nó que os
   suporta. Isso é tedioso para preencher nós gerados, portanto, esse
   auxiliar adiciona esses atributos recursivamente, onde ainda não
   estão definidos, definindo-os para os valores do nó pai. Ele
   funciona recursivamente a partir do *node*.

ast.increment_lineno(node, n=1)

   Incrementa o número da linha de cada nó na árvore, começando em
   *node* por *n*. Isso é útil para "mover código" para um local
   diferente em um arquivo.

ast.copy_location(new_node, old_node)

   Copia o local de origem ("lineno" e "col_offset") de *old_node*
   para *new_node* se possível, e retorna *new_node*.

ast.iter_fields(node)

   Produz uma tupla de "(fieldname, value)" para cada campo em
   "node._fields" que esteja presente em *node*.

ast.iter_child_nodes(node)

   Produz todos os nós filhos diretos de *node*, ou seja, todos os
   campos que são nós e todos os itens de campos que são listas de
   nós.

ast.walk(node)

   Produz recursivamente todos os nós descendentes na árvore começando
   em *node* (incluindo o próprio *node*), em nenhuma ordem
   especificada. Isso é útil se você quiser apenas modificar nós no
   lugar e não se importar com o contexto.

class ast.NodeVisitor

   Uma classe base de visitante de nó que percorre a árvore de sintaxe
   abstrata e chama uma função de visitante para cada nó encontrado.
   Esta função pode retornar um valor que é encaminhado pelo método
   "visit()".

   Esta classe deve ser uma subclasse, com a subclasse adicionando
   métodos visitantes.

   visit(node)

      Visita um nó. A implementação padrão chama o método chamado
      "self.visit_*nomedaclasse*"  sendo *nomedaclasse* o nome da
      classe do nó, ou "generic_visit()" se aquele método não existir.

   generic_visit(node)

      Este visitante chama "visit()" em todos os filhos do nó.

      Observe que nós filhos de nós que possuem um método de visitante
      personalizado não serão visitados, a menos que o visitante chame
      "generic_visit()" ou os visite por conta própria.

   Não use o "NodeVisitor" se você quiser aplicar mudanças nos nós
   durante a travessia. Para isso existe um visitante especial
   ("NodeTransformer") que permite modificações.

class ast.NodeTransformer

   A subclasse "NodeVisitor" que percorre a árvore de sintaxe abstrata
   e permite a modificação de nós.

   O "NodeTransformer" percorrerá a AST e usará o valor de retorno dos
   métodos do visitante para substituir ou remover o nó antigo. Se o
   valor de retorno do método visitante for "None", o nó será removido
   de seu local, caso contrário, ele será substituído pelo valor de
   retorno. O valor de retorno pode ser o nó original, caso em que não
   há substituição.

   Aqui está um exemplo de transformador que rescreve todas as
   ocorrências de procuras por nome ("foo") para "data['foo']":

      class RewriteName(NodeTransformer):

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

   Tenha em mente que, se o nó em que você está operando tiver nós
   filhos, você deve transformar os nós filhos por conta própria ou
   chamar o método "generic_visit()" para o nó primeiro.

   Para nós que faziam parte de uma coleção de instruções (que se
   aplica a todos os nós de instrução), o visitante também pode
   retornar uma lista de nós em vez de apenas um único nó.

   Se "NodeTransformer" introduz novos nós (que não faziam parte da
   árvore original) sem fornecer informações de localização (como
   "lineno"), "fix_missing_locations()" deve ser chamado com o novo
   subárvore para recalcular as informações de localização:

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

   Normalmente você usa o transformador assim:

      node = YourTransformer().visit(node)

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

   Retorne um despejo formatado da árvore em *node*. Isso é útil
   principalmente para fins de depuração. Se *annotate_fields* for
   verdadeiro (por padrão), a sequência retornada mostrará os nomes e
   os valores para os campos. Se *annotate_fields* for falso, a
   sequência de resultados será mais compacta ao omitir nomes de
   campos não ambíguos. Atributos como números de linha e
   deslocamentos de coluna não são despejados por padrão. Se isso for
   desejado, *include_attributes* pode ser definido como verdadeiro.

Ver também:

  Green Tree Snakes, um recurso de documentação externo, possui bons
  detalhes sobre trabalhar com ASTs do Python.
