diff options
Diffstat (limited to 'mako')
-rw-r--r-- | mako/_ast_util.py | 187 |
1 files changed, 3 insertions, 184 deletions
diff --git a/mako/_ast_util.py b/mako/_ast_util.py index caf5f0c..74c0851 100644 --- a/mako/_ast_util.py +++ b/mako/_ast_util.py @@ -8,45 +8,26 @@ ast ~~~ - The `ast` module helps Python applications to process trees of the Python - abstract syntax grammar. The abstract syntax itself might change with - each Python release; this module helps to find out programmatically what - the current grammar looks like and allows modifications of it. - - An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as - a flag to the `compile()` builtin function or by using the `parse()` - function from this module. The result will be a tree of objects whose - classes all inherit from `ast.AST`. - - A modified abstract syntax tree can be compiled into a Python code object - using the built-in `compile()` function. - - Additionally various helper functions are provided that make working with - the trees simpler. The main intention of the helper functions and this - module in general is to provide an easy to use interface for libraries - that work tightly with the python syntax (template engines for example). - + This is a stripped down version of Armin Ronacher's ast module. :copyright: Copyright 2008 by Armin Ronacher. :license: Python License. """ + + from _ast import Add from _ast import And from _ast import AST from _ast import BitAnd from _ast import BitOr from _ast import BitXor -from _ast import ClassDef from _ast import Div from _ast import Eq -from _ast import Expression from _ast import FloorDiv -from _ast import FunctionDef from _ast import Gt from _ast import GtE from _ast import If from _ast import In -from _ast import Interactive from _ast import Invert from _ast import Is from _ast import IsNot @@ -54,8 +35,6 @@ from _ast import LShift from _ast import Lt from _ast import LtE from _ast import Mod -from _ast import mod -from _ast import Module from _ast import Mult from _ast import Name from _ast import Not @@ -64,7 +43,6 @@ from _ast import NotIn from _ast import Or from _ast import PyCF_ONLY_AST from _ast import RShift -from _ast import Str from _ast import Sub from _ast import UAdd from _ast import USub @@ -114,106 +92,6 @@ def parse(expr, filename="<unknown>", mode="exec"): return compile(expr, filename, mode, PyCF_ONLY_AST) -def to_source(node, indent_with=" " * 4): - """ - This function can convert a node tree back into python sourcecode. This - is useful for debugging purposes, especially if you're dealing with custom - asts not generated by python itself. - - It could be that the sourcecode is evaluable when the AST itself is not - compilable / evaluable. The reason for this is that the AST contains some - more data than regular sourcecode does, which is dropped during - conversion. - - Each level of indentation is replaced with `indent_with`. Per default this - parameter is equal to four spaces as suggested by PEP 8, but it might be - adjusted to match the application's styleguide. - """ - generator = SourceGenerator(indent_with) - generator.visit(node) - return "".join(generator.result) - - -def dump(node): - """ - A very verbose representation of the node passed. This is useful for - debugging purposes. - """ - - def _format(node): - if isinstance(node, AST): - return "%s(%s)" % ( - node.__class__.__name__, - ", ".join( - "%s=%s" % (a, _format(b)) for a, b in iter_fields(node) - ), - ) - elif isinstance(node, list): - return "[%s]" % ", ".join(_format(x) for x in node) - return repr(node) - - if not isinstance(node, AST): - raise TypeError("expected AST, got %r" % node.__class__.__name__) - return _format(node) - - -def copy_location(new_node, old_node): - """ - Copy the source location hint (`lineno` and `col_offset`) from the - old to the new node if possible and return the new one. - """ - for attr in "lineno", "col_offset": - if ( - attr in old_node._attributes - and attr in new_node._attributes - and hasattr(old_node, attr) - ): - setattr(new_node, attr, getattr(old_node, attr)) - return new_node - - -def fix_missing_locations(node): - """ - Some nodes require a line number and the column offset. Without that - information the compiler will abort the compilation. Because it can be - a dull task to add appropriate line numbers and column offsets when - adding new nodes this function can help. It copies the line number and - column offset of the parent node to the child nodes without this - information. - - Unlike `copy_location` this works recursive and won't touch nodes that - already have a location information. - """ - - def _fix(node, lineno, col_offset): - if "lineno" in node._attributes: - if not hasattr(node, "lineno"): - node.lineno = lineno - else: - lineno = node.lineno - if "col_offset" in node._attributes: - if not hasattr(node, "col_offset"): - node.col_offset = col_offset - else: - col_offset = node.col_offset - for child in iter_child_nodes(node): - _fix(child, lineno, col_offset) - - _fix(node, 1, 0) - return node - - -def increment_lineno(node, n=1): - """ - Increment the line numbers of all nodes by `n` if they have line number - attributes. This is useful to "move code" to a different location in a - file. - """ - for node in zip((node,), walk(node)): - if "lineno" in node._attributes: - node.lineno = getattr(node, "lineno", 0) + n - - def iter_fields(node): """Iterate over all fields of a node, only yielding existing fields.""" # CPython 2.5 compat @@ -226,65 +104,6 @@ def iter_fields(node): pass -def get_fields(node): - """Like `iter_fields` but returns a dict.""" - return dict(iter_fields(node)) - - -def iter_child_nodes(node): - """Iterate over all child nodes or a node.""" - for name, field in iter_fields(node): - if isinstance(field, AST): - yield field - elif isinstance(field, list): - for item in field: - if isinstance(item, AST): - yield item - - -def get_child_nodes(node): - """Like `iter_child_nodes` but returns a list.""" - return list(iter_child_nodes(node)) - - -def get_compile_mode(node): - """ - Get the mode for `compile` of a given node. If the node is not a `mod` - node (`Expression`, `Module` etc.) a `TypeError` is thrown. - """ - if not isinstance(node, mod): - raise TypeError("expected mod node, got %r" % node.__class__.__name__) - return {Expression: "eval", Interactive: "single"}.get( - node.__class__, "expr" - ) - - -def get_docstring(node): - """ - Return the docstring for the given node or `None` if no docstring can be - found. If the node provided does not accept docstrings a `TypeError` - will be raised. - """ - if not isinstance(node, (FunctionDef, ClassDef, Module)): - raise TypeError("%r can't have docstrings" % node.__class__.__name__) - if node.body and isinstance(node.body[0], Str): - return node.body[0].s - - -def walk(node): - """ - Iterate over all nodes. This is useful if you only want to modify nodes in - place and don't care about the context or the order the nodes are returned. - """ - from collections import deque - - todo = deque([node]) - while todo: - node = todo.popleft() - todo.extend(iter_child_nodes(node)) - yield node - - class NodeVisitor(object): """ |