cmlenz@794: # -*- coding: utf-8 -*- cmlenz@794: # cmlenz@854: # Copyright (C) 2008-2009 Edgewall Software cmlenz@794: # All rights reserved. cmlenz@794: # cmlenz@794: # This software is licensed as described in the file COPYING, which cmlenz@794: # you should have received as part of this distribution. The terms cmlenz@794: # are also available at http://genshi.edgewall.org/wiki/License. cmlenz@794: # cmlenz@794: # This software consists of voluntary contributions made by many cmlenz@794: # individuals. For the exact contribution history, see the revision cmlenz@794: # history and logs, available at http://genshi.edgewall.org/log/. cmlenz@794: cmlenz@794: """Support classes for generating code from abstract syntax trees.""" cmlenz@794: cmlenz@794: try: cmlenz@794: import _ast cmlenz@794: except ImportError: cmlenz@794: from genshi.template.ast24 import _ast, parse cmlenz@794: else: cmlenz@794: def parse(source, mode): cmlenz@794: return compile(source, '', mode, _ast.PyCF_ONLY_AST) cmlenz@794: cmlenz@794: cmlenz@794: __docformat__ = 'restructuredtext en' cmlenz@794: cmlenz@794: cmlenz@794: class ASTCodeGenerator(object): cmlenz@794: """General purpose base class for AST transformations. cmlenz@794: cmlenz@794: Every visitor method can be overridden to return an AST node that has been cmlenz@794: altered or replaced in some way. cmlenz@794: """ cmlenz@794: def __init__(self, tree): cmlenz@794: self.lines_info = [] cmlenz@794: self.line_info = None cmlenz@794: self.code = '' cmlenz@794: self.line = None cmlenz@794: self.last = None cmlenz@794: self.indent = 0 cmlenz@794: self.blame_stack = [] cmlenz@794: self.visit(tree) cmlenz@794: if self.line.strip(): cmlenz@794: self.code += self.line + '\n' cmlenz@794: self.lines_info.append(self.line_info) cmlenz@794: self.line = None cmlenz@794: self.line_info = None cmlenz@794: cmlenz@794: def _change_indent(self, delta): cmlenz@794: self.indent += delta cmlenz@794: cmlenz@794: def _new_line(self): cmlenz@794: if self.line is not None: cmlenz@794: self.code += self.line + '\n' cmlenz@794: self.lines_info.append(self.line_info) cmlenz@794: self.line = ' '*4*self.indent cmlenz@794: if len(self.blame_stack) == 0: cmlenz@794: self.line_info = [] cmlenz@794: self.last = None cmlenz@794: else: cmlenz@794: self.line_info = [(0, self.blame_stack[-1],)] cmlenz@794: self.last = self.blame_stack[-1] cmlenz@794: cmlenz@794: def _write(self, s): cmlenz@794: if len(s) == 0: cmlenz@794: return cmlenz@794: if len(self.blame_stack) == 0: cmlenz@794: if self.last is not None: cmlenz@794: self.last = None cmlenz@794: self.line_info.append((len(self.line), self.last)) cmlenz@794: else: cmlenz@794: if self.last != self.blame_stack[-1]: cmlenz@794: self.last = self.blame_stack[-1] cmlenz@794: self.line_info.append((len(self.line), self.last)) cmlenz@794: self.line += s cmlenz@794: cmlenz@794: def visit(self, node): cmlenz@794: if node is None: cmlenz@794: return None cmlenz@794: if type(node) is tuple: cmlenz@794: return tuple([self.visit(n) for n in node]) cmlenz@794: try: cmlenz@794: self.blame_stack.append((node.lineno, node.col_offset,)) cmlenz@794: info = True cmlenz@794: except AttributeError: cmlenz@794: info = False cmlenz@794: visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None) cmlenz@794: if visitor is None: cmlenz@794: raise Exception('Unhandled node type %r' % type(node)) cmlenz@794: ret = visitor(node) cmlenz@794: if info: cmlenz@794: self.blame_stack.pop() cmlenz@794: return ret cmlenz@794: cmlenz@794: def visit_Module(self, node): cmlenz@794: for n in node.body: cmlenz@794: self.visit(n) cmlenz@794: visit_Interactive = visit_Module cmlenz@794: visit_Suite = visit_Module cmlenz@794: cmlenz@794: def visit_Expression(self, node): cmlenz@794: self._new_line() cmlenz@794: return self.visit(node.body) cmlenz@794: cmlenz@794: # arguments = (expr* args, identifier? vararg, cmlenz@802: # identifier? kwarg, expr* defaults) cmlenz@794: def visit_arguments(self, node): cmlenz@794: first = True cmlenz@802: no_default_count = len(node.args) - len(node.defaults) cmlenz@794: for i, arg in enumerate(node.args): cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: else: cmlenz@794: first = False cmlenz@794: self.visit(arg) cmlenz@802: if i >= no_default_count: cmlenz@794: self._write('=') cmlenz@802: self.visit(node.defaults[i - no_default_count]) cmlenz@794: if getattr(node, 'vararg', None): cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: else: cmlenz@794: first = False cmlenz@794: self._write('*' + node.vararg) cmlenz@794: if getattr(node, 'kwarg', None): cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: else: cmlenz@794: first = False cmlenz@794: self._write('**' + node.kwarg) cmlenz@794: cmlenz@794: # FunctionDef(identifier name, arguments args, cmlenz@879: # stmt* body, expr* decorator_list) cmlenz@794: def visit_FunctionDef(self, node): cmlenz@879: decarators = () cmlenz@879: if hasattr(node, 'decorator_list'): cmlenz@879: decorators = getattr(node, 'decorator_list') cmlenz@879: else: # different name in earlier Python versions cmlenz@879: decorators = getattr(node, 'decorators', ()) cmlenz@879: for decorator in decorators: cmlenz@794: self._new_line() cmlenz@794: self._write('@') cmlenz@794: self.visit(decorator) cmlenz@794: self._new_line() cmlenz@794: self._write('def ' + node.name + '(') cmlenz@794: self.visit(node.args) cmlenz@794: self._write('):') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # ClassDef(identifier name, expr* bases, stmt* body) cmlenz@794: def visit_ClassDef(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('class ' + node.name) cmlenz@794: if node.bases: cmlenz@794: self._write('(') cmlenz@794: self.visit(node.bases[0]) cmlenz@794: for base in node.bases[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(base) cmlenz@794: self._write(')') cmlenz@794: self._write(':') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # Return(expr? value) cmlenz@794: def visit_Return(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('return') cmlenz@794: if getattr(node, 'value', None): cmlenz@794: self._write(' ') cmlenz@794: self.visit(node.value) cmlenz@794: cmlenz@794: # Delete(expr* targets) cmlenz@794: def visit_Delete(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('del ') cmlenz@794: self.visit(node.targets[0]) cmlenz@794: for target in node.targets[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(target) cmlenz@794: cmlenz@794: # Assign(expr* targets, expr value) cmlenz@794: def visit_Assign(self, node): cmlenz@794: self._new_line() cmlenz@794: for target in node.targets: cmlenz@794: self.visit(target) cmlenz@794: self._write(' = ') cmlenz@794: self.visit(node.value) cmlenz@794: cmlenz@794: # AugAssign(expr target, operator op, expr value) cmlenz@794: def visit_AugAssign(self, node): cmlenz@794: self._new_line() cmlenz@794: self.visit(node.target) cmlenz@794: self._write(' ' + self.binary_operators[node.op.__class__] + '= ') cmlenz@794: self.visit(node.value) cmlenz@794: cmlenz@794: # Print(expr? dest, expr* values, bool nl) cmlenz@794: def visit_Print(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('print') cmlenz@794: if getattr(node, 'dest', None): cmlenz@794: self._write(' >> ') cmlenz@794: self.visit(node.dest) cmlenz@794: if getattr(node, 'values', None): cmlenz@794: self._write(', ') cmlenz@806: else: cmlenz@806: self._write(' ') cmlenz@794: if getattr(node, 'values', None): cmlenz@794: self.visit(node.values[0]) cmlenz@794: for value in node.values[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(value) cmlenz@794: if not node.nl: cmlenz@794: self._write(',') cmlenz@794: cmlenz@794: # For(expr target, expr iter, stmt* body, stmt* orelse) cmlenz@794: def visit_For(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('for ') cmlenz@794: self.visit(node.target) cmlenz@794: self._write(' in ') cmlenz@794: self.visit(node.iter) cmlenz@794: self._write(':') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: if getattr(node, 'orelse', None): cmlenz@794: self._new_line() cmlenz@794: self._write('else:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.orelse: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # While(expr test, stmt* body, stmt* orelse) cmlenz@794: def visit_While(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('while ') cmlenz@794: self.visit(node.test) cmlenz@794: self._write(':') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: if getattr(node, 'orelse', None): cmlenz@794: self._new_line() cmlenz@794: self._write('else:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.orelse: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # If(expr test, stmt* body, stmt* orelse) cmlenz@794: def visit_If(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('if ') cmlenz@794: self.visit(node.test) cmlenz@794: self._write(':') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: if getattr(node, 'orelse', None): cmlenz@794: self._new_line() cmlenz@794: self._write('else:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.orelse: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # With(expr context_expr, expr? optional_vars, stmt* body) cmlenz@794: def visit_With(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('with ') cmlenz@794: self.visit(node.context_expr) cmlenz@794: if getattr(node, 'optional_vars', None): cmlenz@794: self._write(' as ') cmlenz@794: self.visit(node.optional_vars) cmlenz@794: self._write(':') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: cmlenz@794: # Raise(expr? type, expr? inst, expr? tback) cmlenz@794: def visit_Raise(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('raise') cmlenz@794: if not node.type: cmlenz@794: return cmlenz@794: self._write(' ') cmlenz@794: self.visit(node.type) cmlenz@794: if not node.inst: cmlenz@794: return cmlenz@794: self._write(', ') cmlenz@794: self.visit(node.inst) cmlenz@794: if not node.tback: cmlenz@794: return cmlenz@794: self._write(', ') cmlenz@794: self.visit(node.tback) cmlenz@794: cmlenz@794: # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) cmlenz@794: def visit_TryExcept(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('try:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: if getattr(node, 'handlers', None): cmlenz@794: for handler in node.handlers: cmlenz@794: self.visit(handler) cmlenz@794: self._new_line() cmlenz@794: if getattr(node, 'orelse', None): cmlenz@794: self._write('else:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.orelse: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # excepthandler = (expr? type, expr? name, stmt* body) cmlenz@794: def visit_ExceptHandler(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('except') cmlenz@794: if getattr(node, 'type', None): cmlenz@794: self._write(' ') cmlenz@794: self.visit(node.type) cmlenz@794: if getattr(node, 'name', None): cmlenz@794: self._write(', ') cmlenz@794: self.visit(node.name) cmlenz@794: self._write(':') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: visit_excepthandler = visit_ExceptHandler cmlenz@794: cmlenz@794: # TryFinally(stmt* body, stmt* finalbody) cmlenz@794: def visit_TryFinally(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('try:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.body: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: if getattr(node, 'finalbody', None): cmlenz@794: self._new_line() cmlenz@794: self._write('finally:') cmlenz@794: self._change_indent(1) cmlenz@794: for statement in node.finalbody: cmlenz@794: self.visit(statement) cmlenz@794: self._change_indent(-1) cmlenz@794: cmlenz@794: # Assert(expr test, expr? msg) cmlenz@794: def visit_Assert(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('assert ') cmlenz@794: self.visit(node.test) cmlenz@794: if getattr(node, 'msg', None): cmlenz@794: self._write(', ') cmlenz@794: self.visit(node.msg) cmlenz@794: cmlenz@794: def visit_alias(self, node): cmlenz@794: self._write(node.name) cmlenz@794: if getattr(node, 'asname', None): cmlenz@794: self._write(' as ') cmlenz@794: self._write(node.asname) cmlenz@794: cmlenz@794: # Import(alias* names) cmlenz@794: def visit_Import(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('import ') cmlenz@794: self.visit(node.names[0]) cmlenz@794: for name in node.names[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(name) cmlenz@794: cmlenz@794: # ImportFrom(identifier module, alias* names, int? level) cmlenz@794: def visit_ImportFrom(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('from ') cmlenz@794: if node.level: cmlenz@794: self._write('.' * node.level) cmlenz@794: self._write(node.module) cmlenz@794: self._write(' import ') cmlenz@794: self.visit(node.names[0]) cmlenz@794: for name in node.names[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(name) cmlenz@794: cmlenz@794: # Exec(expr body, expr? globals, expr? locals) cmlenz@794: def visit_Exec(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('exec ') cmlenz@794: self.visit(node.body) cmlenz@794: if not node.globals: cmlenz@794: return cmlenz@794: self._write(', ') cmlenz@794: self.visit(node.globals) cmlenz@794: if not node.locals: cmlenz@794: return cmlenz@794: self._write(', ') cmlenz@794: self.visit(node.locals) cmlenz@794: cmlenz@794: # Global(identifier* names) cmlenz@794: def visit_Global(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('global ') cmlenz@794: self.visit(node.names[0]) cmlenz@794: for name in node.names[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(name) cmlenz@794: cmlenz@794: # Expr(expr value) cmlenz@794: def visit_Expr(self, node): cmlenz@794: self._new_line() cmlenz@794: self.visit(node.value) cmlenz@794: cmlenz@794: # Pass cmlenz@794: def visit_Pass(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('pass') cmlenz@794: cmlenz@794: # Break cmlenz@794: def visit_Break(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('break') cmlenz@794: cmlenz@794: # Continue cmlenz@794: def visit_Continue(self, node): cmlenz@794: self._new_line() cmlenz@794: self._write('continue') cmlenz@794: cmlenz@794: ### EXPRESSIONS cmlenz@794: def with_parens(f): cmlenz@794: def _f(self, node): cmlenz@794: self._write('(') cmlenz@794: f(self, node) cmlenz@794: self._write(')') cmlenz@794: return _f cmlenz@794: cmlenz@794: bool_operators = {_ast.And: 'and', _ast.Or: 'or'} cmlenz@794: cmlenz@794: # BoolOp(boolop op, expr* values) cmlenz@794: @with_parens cmlenz@794: def visit_BoolOp(self, node): cmlenz@794: joiner = ' ' + self.bool_operators[node.op.__class__] + ' ' cmlenz@794: self.visit(node.values[0]) cmlenz@794: for value in node.values[1:]: cmlenz@794: self._write(joiner) cmlenz@794: self.visit(value) cmlenz@794: cmlenz@794: binary_operators = { cmlenz@794: _ast.Add: '+', cmlenz@794: _ast.Sub: '-', cmlenz@794: _ast.Mult: '*', cmlenz@794: _ast.Div: '/', cmlenz@794: _ast.Mod: '%', cmlenz@794: _ast.Pow: '**', cmlenz@794: _ast.LShift: '<<', cmlenz@794: _ast.RShift: '>>', cmlenz@794: _ast.BitOr: '|', cmlenz@794: _ast.BitXor: '^', cmlenz@794: _ast.BitAnd: '&', cmlenz@794: _ast.FloorDiv: '//' cmlenz@794: } cmlenz@794: cmlenz@794: # BinOp(expr left, operator op, expr right) cmlenz@794: @with_parens cmlenz@794: def visit_BinOp(self, node): cmlenz@794: self.visit(node.left) cmlenz@794: self._write(' ' + self.binary_operators[node.op.__class__] + ' ') cmlenz@794: self.visit(node.right) cmlenz@794: cmlenz@794: unary_operators = { cmlenz@794: _ast.Invert: '~', cmlenz@794: _ast.Not: 'not', cmlenz@794: _ast.UAdd: '+', cmlenz@794: _ast.USub: '-', cmlenz@794: } cmlenz@794: cmlenz@794: # UnaryOp(unaryop op, expr operand) cmlenz@794: def visit_UnaryOp(self, node): cmlenz@794: self._write(self.unary_operators[node.op.__class__] + ' ') cmlenz@794: self.visit(node.operand) cmlenz@794: cmlenz@794: # Lambda(arguments args, expr body) cmlenz@794: @with_parens cmlenz@794: def visit_Lambda(self, node): cmlenz@794: self._write('lambda ') cmlenz@794: self.visit(node.args) cmlenz@794: self._write(': ') cmlenz@794: self.visit(node.body) cmlenz@794: cmlenz@794: # IfExp(expr test, expr body, expr orelse) cmlenz@794: @with_parens cmlenz@794: def visit_IfExp(self, node): cmlenz@794: self.visit(node.body) cmlenz@794: self._write(' if ') cmlenz@794: self.visit(node.test) cmlenz@794: self._write(' else ') cmlenz@794: self.visit(node.orelse) cmlenz@794: cmlenz@794: # Dict(expr* keys, expr* values) cmlenz@794: def visit_Dict(self, node): cmlenz@794: self._write('{') cmlenz@794: for key, value in zip(node.keys, node.values): cmlenz@794: self.visit(key) cmlenz@794: self._write(': ') cmlenz@794: self.visit(value) cmlenz@794: self._write(', ') cmlenz@794: self._write('}') cmlenz@794: cmlenz@794: # ListComp(expr elt, comprehension* generators) cmlenz@794: def visit_ListComp(self, node): cmlenz@794: self._write('[') cmlenz@794: self.visit(node.elt) cmlenz@794: for generator in node.generators: cmlenz@794: # comprehension = (expr target, expr iter, expr* ifs) cmlenz@794: self._write(' for ') cmlenz@794: self.visit(generator.target) cmlenz@794: self._write(' in ') cmlenz@794: self.visit(generator.iter) cmlenz@794: for ifexpr in generator.ifs: cmlenz@794: self._write(' if ') cmlenz@794: self.visit(ifexpr) cmlenz@794: self._write(']') cmlenz@794: cmlenz@794: # GeneratorExp(expr elt, comprehension* generators) cmlenz@794: def visit_GeneratorExp(self, node): cmlenz@794: self._write('(') cmlenz@794: self.visit(node.elt) cmlenz@794: for generator in node.generators: cmlenz@794: # comprehension = (expr target, expr iter, expr* ifs) cmlenz@794: self._write(' for ') cmlenz@794: self.visit(generator.target) cmlenz@794: self._write(' in ') cmlenz@794: self.visit(generator.iter) cmlenz@794: for ifexpr in generator.ifs: cmlenz@794: self._write(' if ') cmlenz@794: self.visit(ifexpr) cmlenz@794: self._write(')') cmlenz@794: cmlenz@794: # Yield(expr? value) cmlenz@794: def visit_Yield(self, node): cmlenz@794: self._write('yield') cmlenz@794: if getattr(node, 'value', None): cmlenz@794: self._write(' ') cmlenz@794: self.visit(node.value) cmlenz@794: cmlenz@794: comparision_operators = { cmlenz@794: _ast.Eq: '==', cmlenz@794: _ast.NotEq: '!=', cmlenz@794: _ast.Lt: '<', cmlenz@794: _ast.LtE: '<=', cmlenz@794: _ast.Gt: '>', cmlenz@794: _ast.GtE: '>=', cmlenz@794: _ast.Is: 'is', cmlenz@794: _ast.IsNot: 'is not', cmlenz@794: _ast.In: 'in', cmlenz@794: _ast.NotIn: 'not in', cmlenz@794: } cmlenz@794: cmlenz@794: # Compare(expr left, cmpop* ops, expr* comparators) cmlenz@794: @with_parens cmlenz@794: def visit_Compare(self, node): cmlenz@794: self.visit(node.left) cmlenz@794: for op, comparator in zip(node.ops, node.comparators): cmlenz@794: self._write(' ' + self.comparision_operators[op.__class__] + ' ') cmlenz@794: self.visit(comparator) cmlenz@794: cmlenz@794: # Call(expr func, expr* args, keyword* keywords, cmlenz@794: # expr? starargs, expr? kwargs) cmlenz@794: def visit_Call(self, node): cmlenz@794: self.visit(node.func) cmlenz@794: self._write('(') cmlenz@794: first = True cmlenz@794: for arg in node.args: cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: first = False cmlenz@794: self.visit(arg) cmlenz@794: cmlenz@794: for keyword in node.keywords: cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: first = False cmlenz@794: # keyword = (identifier arg, expr value) cmlenz@794: self._write(keyword.arg) cmlenz@794: self._write('=') cmlenz@794: self.visit(keyword.value) cmlenz@794: if getattr(node, 'starargs', None): cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: first = False cmlenz@794: self._write('*') cmlenz@794: self.visit(node.starargs) cmlenz@794: cmlenz@794: if getattr(node, 'kwargs', None): cmlenz@794: if not first: cmlenz@794: self._write(', ') cmlenz@794: first = False cmlenz@794: self._write('**') cmlenz@794: self.visit(node.kwargs) cmlenz@794: self._write(')') cmlenz@794: cmlenz@794: # Repr(expr value) cmlenz@794: def visit_Repr(self, node): cmlenz@794: self._write('`') cmlenz@794: self.visit(node.value) cmlenz@794: self._write('`') cmlenz@794: cmlenz@794: # Num(object n) cmlenz@794: def visit_Num(self, node): cmlenz@794: self._write(repr(node.n)) cmlenz@794: cmlenz@794: # Str(string s) cmlenz@794: def visit_Str(self, node): cmlenz@794: self._write(repr(node.s)) cmlenz@794: cmlenz@794: # Attribute(expr value, identifier attr, expr_context ctx) cmlenz@794: def visit_Attribute(self, node): cmlenz@794: self.visit(node.value) cmlenz@794: self._write('.') cmlenz@794: self._write(node.attr) cmlenz@794: cmlenz@794: # Subscript(expr value, slice slice, expr_context ctx) cmlenz@794: def visit_Subscript(self, node): cmlenz@794: self.visit(node.value) cmlenz@794: self._write('[') cmlenz@794: def _process_slice(node): cmlenz@794: if isinstance(node, _ast.Ellipsis): cmlenz@794: self._write('...') cmlenz@794: elif isinstance(node, _ast.Slice): cmlenz@794: if getattr(node, 'lower', 'None'): cmlenz@794: self.visit(node.lower) cmlenz@794: self._write(':') cmlenz@794: if getattr(node, 'upper', None): cmlenz@794: self.visit(node.upper) cmlenz@794: if getattr(node, 'step', None): cmlenz@794: self._write(':') cmlenz@794: self.visit(node.step) cmlenz@794: elif isinstance(node, _ast.Index): cmlenz@794: self.visit(node.value) cmlenz@794: elif isinstance(node, _ast.ExtSlice): cmlenz@794: self.visit(node.dims[0]) cmlenz@794: for dim in node.dims[1:]: cmlenz@794: self._write(', ') cmlenz@794: self.visit(dim) cmlenz@794: else: cmlenz@855: raise NotImplemented('Slice type not implemented') cmlenz@794: _process_slice(node.slice) cmlenz@794: self._write(']') cmlenz@794: cmlenz@794: # Name(identifier id, expr_context ctx) cmlenz@794: def visit_Name(self, node): cmlenz@794: self._write(node.id) cmlenz@794: cmlenz@794: # List(expr* elts, expr_context ctx) cmlenz@794: def visit_List(self, node): cmlenz@794: self._write('[') cmlenz@794: for elt in node.elts: cmlenz@794: self.visit(elt) cmlenz@794: self._write(', ') cmlenz@794: self._write(']') cmlenz@794: cmlenz@794: # Tuple(expr *elts, expr_context ctx) cmlenz@794: def visit_Tuple(self, node): cmlenz@794: self._write('(') cmlenz@794: for elt in node.elts: cmlenz@794: self.visit(elt) cmlenz@794: self._write(', ') cmlenz@794: self._write(')') cmlenz@794: cmlenz@794: cmlenz@794: class ASTTransformer(object): cmlenz@794: """General purpose base class for AST transformations. cmlenz@794: cmlenz@794: Every visitor method can be overridden to return an AST node that has been cmlenz@794: altered or replaced in some way. cmlenz@794: """ cmlenz@794: cmlenz@794: def visit(self, node): cmlenz@794: if node is None: cmlenz@794: return None cmlenz@794: if type(node) is tuple: cmlenz@794: return tuple([self.visit(n) for n in node]) cmlenz@794: visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None) cmlenz@794: if visitor is None: cmlenz@794: return node cmlenz@794: return visitor(node) cmlenz@794: cmlenz@794: def _clone(self, node): cmlenz@794: clone = node.__class__() cmlenz@794: for name in getattr(clone, '_attributes', ()): cmlenz@794: try: cmlenz@794: setattr(clone, 'name', getattr(node, name)) cmlenz@794: except AttributeError: cmlenz@794: pass cmlenz@794: for name in clone._fields: cmlenz@794: try: cmlenz@794: value = getattr(node, name) cmlenz@794: except AttributeError: cmlenz@794: pass cmlenz@794: else: cmlenz@794: if value is None: cmlenz@794: pass cmlenz@794: elif isinstance(value, list): cmlenz@794: value = [self.visit(x) for x in value] cmlenz@794: elif isinstance(value, tuple): cmlenz@794: value = tuple(self.visit(x) for x in value) cmlenz@794: else: cmlenz@794: value = self.visit(value) cmlenz@794: setattr(clone, name, value) cmlenz@794: return clone cmlenz@794: cmlenz@794: visit_Module = _clone cmlenz@794: visit_Interactive = _clone cmlenz@794: visit_Expression = _clone cmlenz@794: visit_Suite = _clone cmlenz@794: cmlenz@794: visit_FunctionDef = _clone cmlenz@794: visit_ClassDef = _clone cmlenz@794: visit_Return = _clone cmlenz@794: visit_Delete = _clone cmlenz@794: visit_Assign = _clone cmlenz@794: visit_AugAssign = _clone cmlenz@794: visit_Print = _clone cmlenz@794: visit_For = _clone cmlenz@794: visit_While = _clone cmlenz@794: visit_If = _clone cmlenz@794: visit_With = _clone cmlenz@794: visit_Raise = _clone cmlenz@794: visit_TryExcept = _clone cmlenz@794: visit_TryFinally = _clone cmlenz@794: visit_Assert = _clone cmlenz@794: cmlenz@794: visit_Import = _clone cmlenz@794: visit_ImportFrom = _clone cmlenz@794: visit_Exec = _clone cmlenz@794: visit_Global = _clone cmlenz@794: visit_Expr = _clone cmlenz@794: # Pass, Break, Continue don't need to be copied cmlenz@794: cmlenz@794: visit_BoolOp = _clone cmlenz@794: visit_BinOp = _clone cmlenz@794: visit_UnaryOp = _clone cmlenz@794: visit_Lambda = _clone cmlenz@794: visit_IfExp = _clone cmlenz@794: visit_Dict = _clone cmlenz@794: visit_ListComp = _clone cmlenz@794: visit_GeneratorExp = _clone cmlenz@794: visit_Yield = _clone cmlenz@794: visit_Compare = _clone cmlenz@794: visit_Call = _clone cmlenz@794: visit_Repr = _clone cmlenz@794: # Num, Str don't need to be copied cmlenz@794: cmlenz@794: visit_Attribute = _clone cmlenz@794: visit_Subscript = _clone cmlenz@794: visit_Name = _clone cmlenz@794: visit_List = _clone cmlenz@794: visit_Tuple = _clone cmlenz@794: cmlenz@794: visit_comprehension = _clone cmlenz@794: visit_excepthandler = _clone cmlenz@794: visit_arguments = _clone cmlenz@794: visit_keyword = _clone cmlenz@794: visit_alias = _clone cmlenz@794: cmlenz@794: visit_Slice = _clone cmlenz@794: visit_ExtSlice = _clone cmlenz@794: visit_Index = _clone cmlenz@794: cmlenz@794: del _clone