| [945] | 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | # |
|---|
| [1120] | 3 | # Copyright (C) 2008-2010 Edgewall Software |
|---|
| [945] | 4 | # All rights reserved. |
|---|
| 5 | # |
|---|
| 6 | # This software is licensed as described in the file COPYING, which |
|---|
| 7 | # you should have received as part of this distribution. The terms |
|---|
| 8 | # are also available at http://genshi.edgewall.org/wiki/License. |
|---|
| 9 | # |
|---|
| 10 | # This software consists of voluntary contributions made by many |
|---|
| 11 | # individuals. For the exact contribution history, see the revision |
|---|
| 12 | # history and logs, available at http://genshi.edgewall.org/log/. |
|---|
| 13 | |
|---|
| [978] | 14 | """Support classes for generating code from abstract syntax trees.""" |
|---|
| [945] | 15 | |
|---|
| [975] | 16 | try: |
|---|
| 17 | import _ast |
|---|
| 18 | except ImportError: |
|---|
| [981] | 19 | from genshi.template.ast24 import _ast, parse |
|---|
| 20 | else: |
|---|
| 21 | def parse(source, mode): |
|---|
| 22 | return compile(source, '', mode, _ast.PyCF_ONLY_AST) |
|---|
| 23 | |
|---|
| [1249] | 24 | from genshi.compat import IS_PYTHON2, isstring |
|---|
| [981] | 25 | |
|---|
| [945] | 26 | __docformat__ = 'restructuredtext en' |
|---|
| 27 | |
|---|
| [942] | 28 | |
|---|
| [978] | 29 | class ASTCodeGenerator(object): |
|---|
| [942] | 30 | """General purpose base class for AST transformations. |
|---|
| [973] | 31 | |
|---|
| [942] | 32 | Every visitor method can be overridden to return an AST node that has been |
|---|
| 33 | altered or replaced in some way. |
|---|
| 34 | """ |
|---|
| 35 | def __init__(self, tree): |
|---|
| 36 | self.lines_info = [] |
|---|
| 37 | self.line_info = None |
|---|
| [980] | 38 | self.code = '' |
|---|
| [942] | 39 | self.line = None |
|---|
| 40 | self.last = None |
|---|
| 41 | self.indent = 0 |
|---|
| 42 | self.blame_stack = [] |
|---|
| 43 | self.visit(tree) |
|---|
| [977] | 44 | if self.line.strip(): |
|---|
| [980] | 45 | self.code += self.line + '\n' |
|---|
| [942] | 46 | self.lines_info.append(self.line_info) |
|---|
| 47 | self.line = None |
|---|
| 48 | self.line_info = None |
|---|
| 49 | |
|---|
| [978] | 50 | def _change_indent(self, delta): |
|---|
| 51 | self.indent += delta |
|---|
| [973] | 52 | |
|---|
| [978] | 53 | def _new_line(self): |
|---|
| [942] | 54 | if self.line is not None: |
|---|
| 55 | self.code += self.line + '\n' |
|---|
| 56 | self.lines_info.append(self.line_info) |
|---|
| 57 | self.line = ' '*4*self.indent |
|---|
| 58 | if len(self.blame_stack) == 0: |
|---|
| 59 | self.line_info = [] |
|---|
| 60 | self.last = None |
|---|
| 61 | else: |
|---|
| 62 | self.line_info = [(0, self.blame_stack[-1],)] |
|---|
| 63 | self.last = self.blame_stack[-1] |
|---|
| 64 | |
|---|
| [978] | 65 | def _write(self, s): |
|---|
| [942] | 66 | if len(s) == 0: |
|---|
| 67 | return |
|---|
| 68 | if len(self.blame_stack) == 0: |
|---|
| 69 | if self.last is not None: |
|---|
| 70 | self.last = None |
|---|
| 71 | self.line_info.append((len(self.line), self.last)) |
|---|
| 72 | else: |
|---|
| 73 | if self.last != self.blame_stack[-1]: |
|---|
| 74 | self.last = self.blame_stack[-1] |
|---|
| 75 | self.line_info.append((len(self.line), self.last)) |
|---|
| 76 | self.line += s |
|---|
| 77 | |
|---|
| 78 | def visit(self, node): |
|---|
| 79 | if node is None: |
|---|
| 80 | return None |
|---|
| 81 | if type(node) is tuple: |
|---|
| 82 | return tuple([self.visit(n) for n in node]) |
|---|
| 83 | try: |
|---|
| 84 | self.blame_stack.append((node.lineno, node.col_offset,)) |
|---|
| 85 | info = True |
|---|
| 86 | except AttributeError: |
|---|
| 87 | info = False |
|---|
| [978] | 88 | visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None) |
|---|
| 89 | if visitor is None: |
|---|
| 90 | raise Exception('Unhandled node type %r' % type(node)) |
|---|
| [942] | 91 | ret = visitor(node) |
|---|
| 92 | if info: |
|---|
| 93 | self.blame_stack.pop() |
|---|
| 94 | return ret |
|---|
| 95 | |
|---|
| [978] | 96 | def visit_Module(self, node): |
|---|
| [942] | 97 | for n in node.body: |
|---|
| 98 | self.visit(n) |
|---|
| [978] | 99 | visit_Interactive = visit_Module |
|---|
| 100 | visit_Suite = visit_Module |
|---|
| [942] | 101 | |
|---|
| [978] | 102 | def visit_Expression(self, node): |
|---|
| 103 | self._new_line() |
|---|
| [942] | 104 | return self.visit(node.body) |
|---|
| 105 | |
|---|
| [1249] | 106 | # Python < 3.4 |
|---|
| [973] | 107 | # arguments = (expr* args, identifier? vararg, |
|---|
| [1004] | 108 | # identifier? kwarg, expr* defaults) |
|---|
| [1249] | 109 | # |
|---|
| 110 | # Python >= 3.4 |
|---|
| 111 | # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, |
|---|
| 112 | # arg? kwarg, expr* defaults) |
|---|
| [978] | 113 | def visit_arguments(self, node): |
|---|
| [1250] | 114 | def write_possible_comma(): |
|---|
| 115 | if _first[0]: |
|---|
| 116 | _first[0] = False |
|---|
| 117 | else: |
|---|
| [978] | 118 | self._write(', ') |
|---|
| [1250] | 119 | _first = [True] |
|---|
| 120 | |
|---|
| 121 | def write_args(args, defaults): |
|---|
| 122 | no_default_count = len(args) - len(defaults) |
|---|
| 123 | for i, arg in enumerate(args): |
|---|
| 124 | write_possible_comma() |
|---|
| 125 | self.visit(arg) |
|---|
| 126 | default_idx = i - no_default_count |
|---|
| 127 | if default_idx >= 0 and defaults[default_idx] is not None: |
|---|
| 128 | self._write('=') |
|---|
| 129 | self.visit(defaults[i - no_default_count]) |
|---|
| 130 | |
|---|
| 131 | write_args(node.args, node.defaults) |
|---|
| [942] | 132 | if getattr(node, 'vararg', None): |
|---|
| [1250] | 133 | write_possible_comma() |
|---|
| [1249] | 134 | self._write('*') |
|---|
| 135 | if isstring(node.vararg): |
|---|
| 136 | self._write(node.vararg) |
|---|
| 137 | else: |
|---|
| 138 | self.visit(node.vararg) |
|---|
| [1250] | 139 | if getattr(node, 'kwonlyargs', None): |
|---|
| 140 | write_args(node.kwonlyargs, node.kw_defaults) |
|---|
| [942] | 141 | if getattr(node, 'kwarg', None): |
|---|
| [1250] | 142 | write_possible_comma() |
|---|
| [1249] | 143 | self._write('**') |
|---|
| 144 | if isstring(node.kwarg): |
|---|
| 145 | self._write(node.kwarg) |
|---|
| 146 | else: |
|---|
| 147 | self.visit(node.kwarg) |
|---|
| [942] | 148 | |
|---|
| [1159] | 149 | if not IS_PYTHON2: |
|---|
| 150 | # In Python 3 arguments get a special node |
|---|
| 151 | def visit_arg(self, node): |
|---|
| 152 | self._write(node.arg) |
|---|
| 153 | |
|---|
| [973] | 154 | # FunctionDef(identifier name, arguments args, |
|---|
| [1102] | 155 | # stmt* body, expr* decorator_list) |
|---|
| [978] | 156 | def visit_FunctionDef(self, node): |
|---|
| [1102] | 157 | decarators = () |
|---|
| 158 | if hasattr(node, 'decorator_list'): |
|---|
| 159 | decorators = getattr(node, 'decorator_list') |
|---|
| 160 | else: # different name in earlier Python versions |
|---|
| 161 | decorators = getattr(node, 'decorators', ()) |
|---|
| 162 | for decorator in decorators: |
|---|
| [978] | 163 | self._new_line() |
|---|
| 164 | self._write('@') |
|---|
| [942] | 165 | self.visit(decorator) |
|---|
| [978] | 166 | self._new_line() |
|---|
| [980] | 167 | self._write('def ' + node.name + '(') |
|---|
| [942] | 168 | self.visit(node.args) |
|---|
| [980] | 169 | self._write('):') |
|---|
| [978] | 170 | self._change_indent(1) |
|---|
| [942] | 171 | for statement in node.body: |
|---|
| 172 | self.visit(statement) |
|---|
| [978] | 173 | self._change_indent(-1) |
|---|
| [942] | 174 | |
|---|
| 175 | # ClassDef(identifier name, expr* bases, stmt* body) |
|---|
| [978] | 176 | def visit_ClassDef(self, node): |
|---|
| 177 | self._new_line() |
|---|
| [980] | 178 | self._write('class ' + node.name) |
|---|
| [942] | 179 | if node.bases: |
|---|
| [978] | 180 | self._write('(') |
|---|
| [942] | 181 | self.visit(node.bases[0]) |
|---|
| 182 | for base in node.bases[1:]: |
|---|
| [978] | 183 | self._write(', ') |
|---|
| [942] | 184 | self.visit(base) |
|---|
| [978] | 185 | self._write(')') |
|---|
| 186 | self._write(':') |
|---|
| 187 | self._change_indent(1) |
|---|
| [942] | 188 | for statement in node.body: |
|---|
| 189 | self.visit(statement) |
|---|
| [978] | 190 | self._change_indent(-1) |
|---|
| 191 | |
|---|
| [942] | 192 | # Return(expr? value) |
|---|
| [978] | 193 | def visit_Return(self, node): |
|---|
| 194 | self._new_line() |
|---|
| [980] | 195 | self._write('return') |
|---|
| [942] | 196 | if getattr(node, 'value', None): |
|---|
| [980] | 197 | self._write(' ') |
|---|
| [942] | 198 | self.visit(node.value) |
|---|
| [978] | 199 | |
|---|
| [942] | 200 | # Delete(expr* targets) |
|---|
| [978] | 201 | def visit_Delete(self, node): |
|---|
| 202 | self._new_line() |
|---|
| [980] | 203 | self._write('del ') |
|---|
| [942] | 204 | self.visit(node.targets[0]) |
|---|
| 205 | for target in node.targets[1:]: |
|---|
| [980] | 206 | self._write(', ') |
|---|
| [942] | 207 | self.visit(target) |
|---|
| 208 | |
|---|
| 209 | # Assign(expr* targets, expr value) |
|---|
| [978] | 210 | def visit_Assign(self, node): |
|---|
| 211 | self._new_line() |
|---|
| [942] | 212 | for target in node.targets: |
|---|
| 213 | self.visit(target) |
|---|
| [978] | 214 | self._write(' = ') |
|---|
| [942] | 215 | self.visit(node.value) |
|---|
| 216 | |
|---|
| 217 | # AugAssign(expr target, operator op, expr value) |
|---|
| [978] | 218 | def visit_AugAssign(self, node): |
|---|
| 219 | self._new_line() |
|---|
| [942] | 220 | self.visit(node.target) |
|---|
| [980] | 221 | self._write(' ' + self.binary_operators[node.op.__class__] + '= ') |
|---|
| [942] | 222 | self.visit(node.value) |
|---|
| 223 | |
|---|
| 224 | # Print(expr? dest, expr* values, bool nl) |
|---|
| [978] | 225 | def visit_Print(self, node): |
|---|
| 226 | self._new_line() |
|---|
| [980] | 227 | self._write('print') |
|---|
| [942] | 228 | if getattr(node, 'dest', None): |
|---|
| [980] | 229 | self._write(' >> ') |
|---|
| [942] | 230 | self.visit(node.dest) |
|---|
| 231 | if getattr(node, 'values', None): |
|---|
| [980] | 232 | self._write(', ') |
|---|
| [1008] | 233 | else: |
|---|
| 234 | self._write(' ') |
|---|
| [942] | 235 | if getattr(node, 'values', None): |
|---|
| 236 | self.visit(node.values[0]) |
|---|
| 237 | for value in node.values[1:]: |
|---|
| [980] | 238 | self._write(', ') |
|---|
| [942] | 239 | self.visit(value) |
|---|
| 240 | if not node.nl: |
|---|
| [980] | 241 | self._write(',') |
|---|
| [942] | 242 | |
|---|
| 243 | # For(expr target, expr iter, stmt* body, stmt* orelse) |
|---|
| [978] | 244 | def visit_For(self, node): |
|---|
| 245 | self._new_line() |
|---|
| [980] | 246 | self._write('for ') |
|---|
| [942] | 247 | self.visit(node.target) |
|---|
| [980] | 248 | self._write(' in ') |
|---|
| [942] | 249 | self.visit(node.iter) |
|---|
| [980] | 250 | self._write(':') |
|---|
| [978] | 251 | self._change_indent(1) |
|---|
| [942] | 252 | for statement in node.body: |
|---|
| 253 | self.visit(statement) |
|---|
| [978] | 254 | self._change_indent(-1) |
|---|
| [942] | 255 | if getattr(node, 'orelse', None): |
|---|
| [978] | 256 | self._new_line() |
|---|
| [980] | 257 | self._write('else:') |
|---|
| [978] | 258 | self._change_indent(1) |
|---|
| [942] | 259 | for statement in node.orelse: |
|---|
| 260 | self.visit(statement) |
|---|
| [978] | 261 | self._change_indent(-1) |
|---|
| [973] | 262 | |
|---|
| [942] | 263 | # While(expr test, stmt* body, stmt* orelse) |
|---|
| [978] | 264 | def visit_While(self, node): |
|---|
| 265 | self._new_line() |
|---|
| [980] | 266 | self._write('while ') |
|---|
| [942] | 267 | self.visit(node.test) |
|---|
| [980] | 268 | self._write(':') |
|---|
| [978] | 269 | self._change_indent(1) |
|---|
| [942] | 270 | for statement in node.body: |
|---|
| 271 | self.visit(statement) |
|---|
| [978] | 272 | self._change_indent(-1) |
|---|
| [942] | 273 | if getattr(node, 'orelse', None): |
|---|
| [978] | 274 | self._new_line() |
|---|
| [980] | 275 | self._write('else:') |
|---|
| [978] | 276 | self._change_indent(1) |
|---|
| [942] | 277 | for statement in node.orelse: |
|---|
| 278 | self.visit(statement) |
|---|
| [978] | 279 | self._change_indent(-1) |
|---|
| [942] | 280 | |
|---|
| 281 | # If(expr test, stmt* body, stmt* orelse) |
|---|
| [978] | 282 | def visit_If(self, node): |
|---|
| 283 | self._new_line() |
|---|
| [980] | 284 | self._write('if ') |
|---|
| [942] | 285 | self.visit(node.test) |
|---|
| [980] | 286 | self._write(':') |
|---|
| [978] | 287 | self._change_indent(1) |
|---|
| [942] | 288 | for statement in node.body: |
|---|
| 289 | self.visit(statement) |
|---|
| [978] | 290 | self._change_indent(-1) |
|---|
| [942] | 291 | if getattr(node, 'orelse', None): |
|---|
| [978] | 292 | self._new_line() |
|---|
| [980] | 293 | self._write('else:') |
|---|
| [978] | 294 | self._change_indent(1) |
|---|
| [942] | 295 | for statement in node.orelse: |
|---|
| 296 | self.visit(statement) |
|---|
| [978] | 297 | self._change_indent(-1) |
|---|
| [942] | 298 | |
|---|
| 299 | # With(expr context_expr, expr? optional_vars, stmt* body) |
|---|
| [1192] | 300 | # With(withitem* items, stmt* body) in Python >= 3.3 |
|---|
| [978] | 301 | def visit_With(self, node): |
|---|
| 302 | self._new_line() |
|---|
| [980] | 303 | self._write('with ') |
|---|
| [1192] | 304 | items = getattr(node, 'items', None) |
|---|
| 305 | first = True |
|---|
| 306 | if items is None: |
|---|
| 307 | items = [node] |
|---|
| 308 | for item in items: |
|---|
| 309 | if not first: |
|---|
| 310 | self._write(', ') |
|---|
| 311 | first = False |
|---|
| 312 | self.visit(item.context_expr) |
|---|
| 313 | if getattr(item, 'optional_vars', None): |
|---|
| 314 | self._write(' as ') |
|---|
| 315 | self.visit(item.optional_vars) |
|---|
| [980] | 316 | self._write(':') |
|---|
| [978] | 317 | self._change_indent(1) |
|---|
| [945] | 318 | for statement in node.body: |
|---|
| 319 | self.visit(statement) |
|---|
| [978] | 320 | self._change_indent(-1) |
|---|
| [942] | 321 | |
|---|
| [1159] | 322 | if IS_PYTHON2: |
|---|
| 323 | # Raise(expr? type, expr? inst, expr? tback) |
|---|
| 324 | def visit_Raise(self, node): |
|---|
| 325 | self._new_line() |
|---|
| 326 | self._write('raise') |
|---|
| 327 | if not node.type: |
|---|
| 328 | return |
|---|
| 329 | self._write(' ') |
|---|
| 330 | self.visit(node.type) |
|---|
| 331 | if not node.inst: |
|---|
| 332 | return |
|---|
| 333 | self._write(', ') |
|---|
| 334 | self.visit(node.inst) |
|---|
| 335 | if not node.tback: |
|---|
| 336 | return |
|---|
| 337 | self._write(', ') |
|---|
| 338 | self.visit(node.tback) |
|---|
| 339 | else: |
|---|
| 340 | # Raise(expr? exc from expr? cause) |
|---|
| 341 | def visit_Raise(self, node): |
|---|
| 342 | self._new_line() |
|---|
| 343 | self._write('raise') |
|---|
| 344 | if not node.exc: |
|---|
| 345 | return |
|---|
| 346 | self._write(' ') |
|---|
| 347 | self.visit(node.exc) |
|---|
| 348 | if not node.cause: |
|---|
| 349 | return |
|---|
| 350 | self._write(' from ') |
|---|
| 351 | self.visit(node.cause) |
|---|
| [942] | 352 | |
|---|
| 353 | # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) |
|---|
| [978] | 354 | def visit_TryExcept(self, node): |
|---|
| 355 | self._new_line() |
|---|
| [980] | 356 | self._write('try:') |
|---|
| [978] | 357 | self._change_indent(1) |
|---|
| [942] | 358 | for statement in node.body: |
|---|
| 359 | self.visit(statement) |
|---|
| [978] | 360 | self._change_indent(-1) |
|---|
| [942] | 361 | if getattr(node, 'handlers', None): |
|---|
| 362 | for handler in node.handlers: |
|---|
| 363 | self.visit(handler) |
|---|
| [978] | 364 | self._new_line() |
|---|
| [942] | 365 | if getattr(node, 'orelse', None): |
|---|
| [980] | 366 | self._write('else:') |
|---|
| [978] | 367 | self._change_indent(1) |
|---|
| [942] | 368 | for statement in node.orelse: |
|---|
| 369 | self.visit(statement) |
|---|
| [978] | 370 | self._change_indent(-1) |
|---|
| [942] | 371 | |
|---|
| [974] | 372 | # excepthandler = (expr? type, expr? name, stmt* body) |
|---|
| [978] | 373 | def visit_ExceptHandler(self, node): |
|---|
| 374 | self._new_line() |
|---|
| [980] | 375 | self._write('except') |
|---|
| [974] | 376 | if getattr(node, 'type', None): |
|---|
| [978] | 377 | self._write(' ') |
|---|
| [974] | 378 | self.visit(node.type) |
|---|
| 379 | if getattr(node, 'name', None): |
|---|
| [978] | 380 | self._write(', ') |
|---|
| [974] | 381 | self.visit(node.name) |
|---|
| [980] | 382 | self._write(':') |
|---|
| [978] | 383 | self._change_indent(1) |
|---|
| [974] | 384 | for statement in node.body: |
|---|
| 385 | self.visit(statement) |
|---|
| [978] | 386 | self._change_indent(-1) |
|---|
| 387 | visit_excepthandler = visit_ExceptHandler |
|---|
| [974] | 388 | |
|---|
| [942] | 389 | # TryFinally(stmt* body, stmt* finalbody) |
|---|
| [978] | 390 | def visit_TryFinally(self, node): |
|---|
| 391 | self._new_line() |
|---|
| [980] | 392 | self._write('try:') |
|---|
| [978] | 393 | self._change_indent(1) |
|---|
| [942] | 394 | for statement in node.body: |
|---|
| 395 | self.visit(statement) |
|---|
| [978] | 396 | self._change_indent(-1) |
|---|
| [942] | 397 | |
|---|
| 398 | if getattr(node, 'finalbody', None): |
|---|
| [978] | 399 | self._new_line() |
|---|
| [980] | 400 | self._write('finally:') |
|---|
| [978] | 401 | self._change_indent(1) |
|---|
| [942] | 402 | for statement in node.finalbody: |
|---|
| 403 | self.visit(statement) |
|---|
| [978] | 404 | self._change_indent(-1) |
|---|
| [942] | 405 | |
|---|
| [1192] | 406 | # New in Py3.3 |
|---|
| 407 | # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) |
|---|
| 408 | def visit_Try(self, node): |
|---|
| 409 | self._new_line() |
|---|
| 410 | self._write('try:') |
|---|
| 411 | self._change_indent(1) |
|---|
| 412 | for statement in node.body: |
|---|
| 413 | self.visit(statement) |
|---|
| 414 | self._change_indent(-1) |
|---|
| 415 | if getattr(node, 'handlers', None): |
|---|
| 416 | for handler in node.handlers: |
|---|
| 417 | self.visit(handler) |
|---|
| 418 | self._new_line() |
|---|
| 419 | if getattr(node, 'orelse', None): |
|---|
| 420 | self._write('else:') |
|---|
| 421 | self._change_indent(1) |
|---|
| 422 | for statement in node.orelse: |
|---|
| 423 | self.visit(statement) |
|---|
| 424 | self._change_indent(-1) |
|---|
| 425 | if getattr(node, 'finalbody', None): |
|---|
| 426 | self._new_line() |
|---|
| 427 | self._write('finally:') |
|---|
| 428 | self._change_indent(1) |
|---|
| 429 | for statement in node.finalbody: |
|---|
| 430 | self.visit(statement) |
|---|
| 431 | self._change_indent(-1) |
|---|
| 432 | |
|---|
| [942] | 433 | # Assert(expr test, expr? msg) |
|---|
| [978] | 434 | def visit_Assert(self, node): |
|---|
| 435 | self._new_line() |
|---|
| [980] | 436 | self._write('assert ') |
|---|
| [942] | 437 | self.visit(node.test) |
|---|
| 438 | if getattr(node, 'msg', None): |
|---|
| [980] | 439 | self._write(', ') |
|---|
| [942] | 440 | self.visit(node.msg) |
|---|
| 441 | |
|---|
| [978] | 442 | def visit_alias(self, node): |
|---|
| 443 | self._write(node.name) |
|---|
| [942] | 444 | if getattr(node, 'asname', None): |
|---|
| [980] | 445 | self._write(' as ') |
|---|
| [978] | 446 | self._write(node.asname) |
|---|
| [942] | 447 | |
|---|
| 448 | # Import(alias* names) |
|---|
| [978] | 449 | def visit_Import(self, node): |
|---|
| 450 | self._new_line() |
|---|
| [980] | 451 | self._write('import ') |
|---|
| [942] | 452 | self.visit(node.names[0]) |
|---|
| 453 | for name in node.names[1:]: |
|---|
| [980] | 454 | self._write(', ') |
|---|
| [942] | 455 | self.visit(name) |
|---|
| [973] | 456 | |
|---|
| [942] | 457 | # ImportFrom(identifier module, alias* names, int? level) |
|---|
| [978] | 458 | def visit_ImportFrom(self, node): |
|---|
| 459 | self._new_line() |
|---|
| [980] | 460 | self._write('from ') |
|---|
| [962] | 461 | if node.level: |
|---|
| [980] | 462 | self._write('.' * node.level) |
|---|
| [978] | 463 | self._write(node.module) |
|---|
| [980] | 464 | self._write(' import ') |
|---|
| [942] | 465 | self.visit(node.names[0]) |
|---|
| 466 | for name in node.names[1:]: |
|---|
| [980] | 467 | self._write(', ') |
|---|
| [942] | 468 | self.visit(name) |
|---|
| 469 | |
|---|
| 470 | # Exec(expr body, expr? globals, expr? locals) |
|---|
| [978] | 471 | def visit_Exec(self, node): |
|---|
| 472 | self._new_line() |
|---|
| [980] | 473 | self._write('exec ') |
|---|
| [942] | 474 | self.visit(node.body) |
|---|
| 475 | if not node.globals: |
|---|
| 476 | return |
|---|
| [980] | 477 | self._write(', ') |
|---|
| [942] | 478 | self.visit(node.globals) |
|---|
| 479 | if not node.locals: |
|---|
| 480 | return |
|---|
| [980] | 481 | self._write(', ') |
|---|
| [942] | 482 | self.visit(node.locals) |
|---|
| 483 | |
|---|
| 484 | # Global(identifier* names) |
|---|
| [978] | 485 | def visit_Global(self, node): |
|---|
| 486 | self._new_line() |
|---|
| [980] | 487 | self._write('global ') |
|---|
| [942] | 488 | self.visit(node.names[0]) |
|---|
| 489 | for name in node.names[1:]: |
|---|
| [980] | 490 | self._write(', ') |
|---|
| [942] | 491 | self.visit(name) |
|---|
| 492 | |
|---|
| 493 | # Expr(expr value) |
|---|
| [978] | 494 | def visit_Expr(self, node): |
|---|
| 495 | self._new_line() |
|---|
| [942] | 496 | self.visit(node.value) |
|---|
| 497 | |
|---|
| 498 | # Pass |
|---|
| [978] | 499 | def visit_Pass(self, node): |
|---|
| 500 | self._new_line() |
|---|
| [980] | 501 | self._write('pass') |
|---|
| [942] | 502 | |
|---|
| 503 | # Break |
|---|
| [978] | 504 | def visit_Break(self, node): |
|---|
| 505 | self._new_line() |
|---|
| [980] | 506 | self._write('break') |
|---|
| [942] | 507 | |
|---|
| 508 | # Continue |
|---|
| [978] | 509 | def visit_Continue(self, node): |
|---|
| 510 | self._new_line() |
|---|
| [980] | 511 | self._write('continue') |
|---|
| [942] | 512 | |
|---|
| 513 | ### EXPRESSIONS |
|---|
| [980] | 514 | def with_parens(f): |
|---|
| [942] | 515 | def _f(self, node): |
|---|
| [978] | 516 | self._write('(') |
|---|
| [942] | 517 | f(self, node) |
|---|
| [978] | 518 | self._write(')') |
|---|
| [942] | 519 | return _f |
|---|
| 520 | |
|---|
| [977] | 521 | bool_operators = {_ast.And: 'and', _ast.Or: 'or'} |
|---|
| 522 | |
|---|
| [942] | 523 | # BoolOp(boolop op, expr* values) |
|---|
| [980] | 524 | @with_parens |
|---|
| [978] | 525 | def visit_BoolOp(self, node): |
|---|
| [980] | 526 | joiner = ' ' + self.bool_operators[node.op.__class__] + ' ' |
|---|
| [942] | 527 | self.visit(node.values[0]) |
|---|
| 528 | for value in node.values[1:]: |
|---|
| [978] | 529 | self._write(joiner) |
|---|
| [942] | 530 | self.visit(value) |
|---|
| 531 | |
|---|
| 532 | binary_operators = { |
|---|
| [973] | 533 | _ast.Add: '+', |
|---|
| 534 | _ast.Sub: '-', |
|---|
| 535 | _ast.Mult: '*', |
|---|
| 536 | _ast.Div: '/', |
|---|
| 537 | _ast.Mod: '%', |
|---|
| 538 | _ast.Pow: '**', |
|---|
| 539 | _ast.LShift: '<<', |
|---|
| 540 | _ast.RShift: '>>', |
|---|
| 541 | _ast.BitOr: '|', |
|---|
| 542 | _ast.BitXor: '^', |
|---|
| 543 | _ast.BitAnd: '&', |
|---|
| 544 | _ast.FloorDiv: '//' |
|---|
| 545 | } |
|---|
| 546 | |
|---|
| [942] | 547 | # BinOp(expr left, operator op, expr right) |
|---|
| [980] | 548 | @with_parens |
|---|
| [978] | 549 | def visit_BinOp(self, node): |
|---|
| [942] | 550 | self.visit(node.left) |
|---|
| [980] | 551 | self._write(' ' + self.binary_operators[node.op.__class__] + ' ') |
|---|
| [942] | 552 | self.visit(node.right) |
|---|
| 553 | |
|---|
| 554 | unary_operators = { |
|---|
| [973] | 555 | _ast.Invert: '~', |
|---|
| 556 | _ast.Not: 'not', |
|---|
| 557 | _ast.UAdd: '+', |
|---|
| 558 | _ast.USub: '-', |
|---|
| 559 | } |
|---|
| [942] | 560 | |
|---|
| 561 | # UnaryOp(unaryop op, expr operand) |
|---|
| [978] | 562 | def visit_UnaryOp(self, node): |
|---|
| [980] | 563 | self._write(self.unary_operators[node.op.__class__] + ' ') |
|---|
| [942] | 564 | self.visit(node.operand) |
|---|
| 565 | |
|---|
| 566 | # Lambda(arguments args, expr body) |
|---|
| [980] | 567 | @with_parens |
|---|
| [978] | 568 | def visit_Lambda(self, node): |
|---|
| 569 | self._write('lambda ') |
|---|
| [942] | 570 | self.visit(node.args) |
|---|
| [978] | 571 | self._write(': ') |
|---|
| [942] | 572 | self.visit(node.body) |
|---|
| 573 | |
|---|
| 574 | # IfExp(expr test, expr body, expr orelse) |
|---|
| [980] | 575 | @with_parens |
|---|
| [978] | 576 | def visit_IfExp(self, node): |
|---|
| [942] | 577 | self.visit(node.body) |
|---|
| [980] | 578 | self._write(' if ') |
|---|
| [942] | 579 | self.visit(node.test) |
|---|
| [980] | 580 | self._write(' else ') |
|---|
| [942] | 581 | self.visit(node.orelse) |
|---|
| 582 | |
|---|
| 583 | # Dict(expr* keys, expr* values) |
|---|
| [978] | 584 | def visit_Dict(self, node): |
|---|
| 585 | self._write('{') |
|---|
| [942] | 586 | for key, value in zip(node.keys, node.values): |
|---|
| 587 | self.visit(key) |
|---|
| [978] | 588 | self._write(': ') |
|---|
| [942] | 589 | self.visit(value) |
|---|
| [978] | 590 | self._write(', ') |
|---|
| 591 | self._write('}') |
|---|
| [942] | 592 | |
|---|
| 593 | # ListComp(expr elt, comprehension* generators) |
|---|
| [978] | 594 | def visit_ListComp(self, node): |
|---|
| [980] | 595 | self._write('[') |
|---|
| [942] | 596 | self.visit(node.elt) |
|---|
| 597 | for generator in node.generators: |
|---|
| 598 | # comprehension = (expr target, expr iter, expr* ifs) |
|---|
| [980] | 599 | self._write(' for ') |
|---|
| [942] | 600 | self.visit(generator.target) |
|---|
| [980] | 601 | self._write(' in ') |
|---|
| [942] | 602 | self.visit(generator.iter) |
|---|
| 603 | for ifexpr in generator.ifs: |
|---|
| [980] | 604 | self._write(' if ') |
|---|
| [942] | 605 | self.visit(ifexpr) |
|---|
| [980] | 606 | self._write(']') |
|---|
| [942] | 607 | |
|---|
| 608 | # GeneratorExp(expr elt, comprehension* generators) |
|---|
| [978] | 609 | def visit_GeneratorExp(self, node): |
|---|
| [980] | 610 | self._write('(') |
|---|
| [942] | 611 | self.visit(node.elt) |
|---|
| 612 | for generator in node.generators: |
|---|
| 613 | # comprehension = (expr target, expr iter, expr* ifs) |
|---|
| [980] | 614 | self._write(' for ') |
|---|
| [942] | 615 | self.visit(generator.target) |
|---|
| [980] | 616 | self._write(' in ') |
|---|
| [942] | 617 | self.visit(generator.iter) |
|---|
| 618 | for ifexpr in generator.ifs: |
|---|
| [980] | 619 | self._write(' if ') |
|---|
| [942] | 620 | self.visit(ifexpr) |
|---|
| [980] | 621 | self._write(')') |
|---|
| [942] | 622 | |
|---|
| 623 | # Yield(expr? value) |
|---|
| [978] | 624 | def visit_Yield(self, node): |
|---|
| [980] | 625 | self._write('yield') |
|---|
| [942] | 626 | if getattr(node, 'value', None): |
|---|
| [980] | 627 | self._write(' ') |
|---|
| [942] | 628 | self.visit(node.value) |
|---|
| 629 | |
|---|
| 630 | comparision_operators = { |
|---|
| [973] | 631 | _ast.Eq: '==', |
|---|
| 632 | _ast.NotEq: '!=', |
|---|
| 633 | _ast.Lt: '<', |
|---|
| 634 | _ast.LtE: '<=', |
|---|
| 635 | _ast.Gt: '>', |
|---|
| 636 | _ast.GtE: '>=', |
|---|
| 637 | _ast.Is: 'is', |
|---|
| 638 | _ast.IsNot: 'is not', |
|---|
| 639 | _ast.In: 'in', |
|---|
| 640 | _ast.NotIn: 'not in', |
|---|
| 641 | } |
|---|
| [942] | 642 | |
|---|
| 643 | # Compare(expr left, cmpop* ops, expr* comparators) |
|---|
| [980] | 644 | @with_parens |
|---|
| [978] | 645 | def visit_Compare(self, node): |
|---|
| [942] | 646 | self.visit(node.left) |
|---|
| 647 | for op, comparator in zip(node.ops, node.comparators): |
|---|
| [980] | 648 | self._write(' ' + self.comparision_operators[op.__class__] + ' ') |
|---|
| [942] | 649 | self.visit(comparator) |
|---|
| 650 | |
|---|
| 651 | # Call(expr func, expr* args, keyword* keywords, |
|---|
| 652 | # expr? starargs, expr? kwargs) |
|---|
| [978] | 653 | def visit_Call(self, node): |
|---|
| [942] | 654 | self.visit(node.func) |
|---|
| [980] | 655 | self._write('(') |
|---|
| [942] | 656 | first = True |
|---|
| 657 | for arg in node.args: |
|---|
| 658 | if not first: |
|---|
| [978] | 659 | self._write(', ') |
|---|
| [942] | 660 | first = False |
|---|
| 661 | self.visit(arg) |
|---|
| 662 | |
|---|
| 663 | for keyword in node.keywords: |
|---|
| 664 | if not first: |
|---|
| [978] | 665 | self._write(', ') |
|---|
| [942] | 666 | first = False |
|---|
| 667 | # keyword = (identifier arg, expr value) |
|---|
| [978] | 668 | self._write(keyword.arg) |
|---|
| 669 | self._write('=') |
|---|
| [942] | 670 | self.visit(keyword.value) |
|---|
| 671 | if getattr(node, 'starargs', None): |
|---|
| 672 | if not first: |
|---|
| [978] | 673 | self._write(', ') |
|---|
| [942] | 674 | first = False |
|---|
| [978] | 675 | self._write('*') |
|---|
| [942] | 676 | self.visit(node.starargs) |
|---|
| [973] | 677 | |
|---|
| [942] | 678 | if getattr(node, 'kwargs', None): |
|---|
| 679 | if not first: |
|---|
| [978] | 680 | self._write(', ') |
|---|
| [942] | 681 | first = False |
|---|
| [978] | 682 | self._write('**') |
|---|
| [942] | 683 | self.visit(node.kwargs) |
|---|
| [978] | 684 | self._write(')') |
|---|
| [942] | 685 | |
|---|
| 686 | # Repr(expr value) |
|---|
| [978] | 687 | def visit_Repr(self, node): |
|---|
| 688 | self._write('`') |
|---|
| [942] | 689 | self.visit(node.value) |
|---|
| [978] | 690 | self._write('`') |
|---|
| [942] | 691 | |
|---|
| 692 | # Num(object n) |
|---|
| [978] | 693 | def visit_Num(self, node): |
|---|
| 694 | self._write(repr(node.n)) |
|---|
| [942] | 695 | |
|---|
| 696 | # Str(string s) |
|---|
| [978] | 697 | def visit_Str(self, node): |
|---|
| 698 | self._write(repr(node.s)) |
|---|
| [942] | 699 | |
|---|
| [1159] | 700 | if not IS_PYTHON2: |
|---|
| 701 | # Bytes(bytes s) |
|---|
| 702 | def visit_Bytes(self, node): |
|---|
| 703 | self._write(repr(node.s)) |
|---|
| 704 | |
|---|
| [942] | 705 | # Attribute(expr value, identifier attr, expr_context ctx) |
|---|
| [978] | 706 | def visit_Attribute(self, node): |
|---|
| [942] | 707 | self.visit(node.value) |
|---|
| [978] | 708 | self._write('.') |
|---|
| 709 | self._write(node.attr) |
|---|
| [973] | 710 | |
|---|
| [942] | 711 | # Subscript(expr value, slice slice, expr_context ctx) |
|---|
| [978] | 712 | def visit_Subscript(self, node): |
|---|
| [942] | 713 | self.visit(node.value) |
|---|
| [978] | 714 | self._write('[') |
|---|
| [942] | 715 | def _process_slice(node): |
|---|
| 716 | if isinstance(node, _ast.Ellipsis): |
|---|
| [978] | 717 | self._write('...') |
|---|
| [942] | 718 | elif isinstance(node, _ast.Slice): |
|---|
| 719 | if getattr(node, 'lower', 'None'): |
|---|
| 720 | self.visit(node.lower) |
|---|
| [978] | 721 | self._write(':') |
|---|
| [942] | 722 | if getattr(node, 'upper', None): |
|---|
| 723 | self.visit(node.upper) |
|---|
| 724 | if getattr(node, 'step', None): |
|---|
| [978] | 725 | self._write(':') |
|---|
| [942] | 726 | self.visit(node.step) |
|---|
| 727 | elif isinstance(node, _ast.Index): |
|---|
| 728 | self.visit(node.value) |
|---|
| 729 | elif isinstance(node, _ast.ExtSlice): |
|---|
| 730 | self.visit(node.dims[0]) |
|---|
| 731 | for dim in node.dims[1:]: |
|---|
| [980] | 732 | self._write(', ') |
|---|
| [942] | 733 | self.visit(dim) |
|---|
| 734 | else: |
|---|
| [1078] | 735 | raise NotImplemented('Slice type not implemented') |
|---|
| [942] | 736 | _process_slice(node.slice) |
|---|
| [978] | 737 | self._write(']') |
|---|
| [942] | 738 | |
|---|
| 739 | # Name(identifier id, expr_context ctx) |
|---|
| [978] | 740 | def visit_Name(self, node): |
|---|
| 741 | self._write(node.id) |
|---|
| [942] | 742 | |
|---|
| [1249] | 743 | # NameConstant(singleton value) |
|---|
| 744 | def visit_NameConstant(self, node): |
|---|
| 745 | if node.value is None: |
|---|
| 746 | self._write('None') |
|---|
| 747 | elif node.value is True: |
|---|
| 748 | self._write('True') |
|---|
| 749 | elif node.value is False: |
|---|
| 750 | self._write('False') |
|---|
| 751 | else: |
|---|
| 752 | raise Exception("Unknown NameConstant %r" % (node.value,)) |
|---|
| 753 | |
|---|
| [942] | 754 | # List(expr* elts, expr_context ctx) |
|---|
| [978] | 755 | def visit_List(self, node): |
|---|
| 756 | self._write('[') |
|---|
| [942] | 757 | for elt in node.elts: |
|---|
| 758 | self.visit(elt) |
|---|
| [980] | 759 | self._write(', ') |
|---|
| [978] | 760 | self._write(']') |
|---|
| [942] | 761 | |
|---|
| 762 | # Tuple(expr *elts, expr_context ctx) |
|---|
| [978] | 763 | def visit_Tuple(self, node): |
|---|
| 764 | self._write('(') |
|---|
| [942] | 765 | for elt in node.elts: |
|---|
| 766 | self.visit(elt) |
|---|
| [980] | 767 | self._write(', ') |
|---|
| [978] | 768 | self._write(')') |
|---|
| [942] | 769 | |
|---|
| 770 | |
|---|
| [978] | 771 | class ASTTransformer(object): |
|---|
| 772 | """General purpose base class for AST transformations. |
|---|
| 773 | |
|---|
| 774 | Every visitor method can be overridden to return an AST node that has been |
|---|
| 775 | altered or replaced in some way. |
|---|
| 776 | """ |
|---|
| [942] | 777 | |
|---|
| [978] | 778 | def visit(self, node): |
|---|
| 779 | if node is None: |
|---|
| 780 | return None |
|---|
| 781 | if type(node) is tuple: |
|---|
| 782 | return tuple([self.visit(n) for n in node]) |
|---|
| 783 | visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None) |
|---|
| 784 | if visitor is None: |
|---|
| 785 | return node |
|---|
| 786 | return visitor(node) |
|---|
| [973] | 787 | |
|---|
| [978] | 788 | def _clone(self, node): |
|---|
| 789 | clone = node.__class__() |
|---|
| 790 | for name in getattr(clone, '_attributes', ()): |
|---|
| 791 | try: |
|---|
| [1167] | 792 | setattr(clone, name, getattr(node, name)) |
|---|
| [978] | 793 | except AttributeError: |
|---|
| 794 | pass |
|---|
| 795 | for name in clone._fields: |
|---|
| 796 | try: |
|---|
| 797 | value = getattr(node, name) |
|---|
| 798 | except AttributeError: |
|---|
| 799 | pass |
|---|
| 800 | else: |
|---|
| 801 | if value is None: |
|---|
| 802 | pass |
|---|
| 803 | elif isinstance(value, list): |
|---|
| 804 | value = [self.visit(x) for x in value] |
|---|
| 805 | elif isinstance(value, tuple): |
|---|
| 806 | value = tuple(self.visit(x) for x in value) |
|---|
| 807 | else: |
|---|
| 808 | value = self.visit(value) |
|---|
| 809 | setattr(clone, name, value) |
|---|
| 810 | return clone |
|---|
| 811 | |
|---|
| 812 | visit_Module = _clone |
|---|
| 813 | visit_Interactive = _clone |
|---|
| 814 | visit_Expression = _clone |
|---|
| 815 | visit_Suite = _clone |
|---|
| 816 | |
|---|
| 817 | visit_FunctionDef = _clone |
|---|
| 818 | visit_ClassDef = _clone |
|---|
| 819 | visit_Return = _clone |
|---|
| 820 | visit_Delete = _clone |
|---|
| 821 | visit_Assign = _clone |
|---|
| 822 | visit_AugAssign = _clone |
|---|
| 823 | visit_Print = _clone |
|---|
| 824 | visit_For = _clone |
|---|
| 825 | visit_While = _clone |
|---|
| 826 | visit_If = _clone |
|---|
| 827 | visit_With = _clone |
|---|
| 828 | visit_Raise = _clone |
|---|
| 829 | visit_TryExcept = _clone |
|---|
| 830 | visit_TryFinally = _clone |
|---|
| [1192] | 831 | visit_Try = _clone |
|---|
| [978] | 832 | visit_Assert = _clone |
|---|
| [1104] | 833 | visit_ExceptHandler = _clone |
|---|
| [978] | 834 | |
|---|
| 835 | visit_Import = _clone |
|---|
| 836 | visit_ImportFrom = _clone |
|---|
| 837 | visit_Exec = _clone |
|---|
| 838 | visit_Global = _clone |
|---|
| 839 | visit_Expr = _clone |
|---|
| 840 | # Pass, Break, Continue don't need to be copied |
|---|
| 841 | |
|---|
| 842 | visit_BoolOp = _clone |
|---|
| 843 | visit_BinOp = _clone |
|---|
| 844 | visit_UnaryOp = _clone |
|---|
| 845 | visit_Lambda = _clone |
|---|
| 846 | visit_IfExp = _clone |
|---|
| 847 | visit_Dict = _clone |
|---|
| 848 | visit_ListComp = _clone |
|---|
| 849 | visit_GeneratorExp = _clone |
|---|
| 850 | visit_Yield = _clone |
|---|
| 851 | visit_Compare = _clone |
|---|
| 852 | visit_Call = _clone |
|---|
| 853 | visit_Repr = _clone |
|---|
| 854 | # Num, Str don't need to be copied |
|---|
| 855 | |
|---|
| 856 | visit_Attribute = _clone |
|---|
| 857 | visit_Subscript = _clone |
|---|
| 858 | visit_Name = _clone |
|---|
| [1249] | 859 | visit_NameConstant = _clone |
|---|
| [978] | 860 | visit_List = _clone |
|---|
| 861 | visit_Tuple = _clone |
|---|
| 862 | |
|---|
| 863 | visit_comprehension = _clone |
|---|
| 864 | visit_excepthandler = _clone |
|---|
| 865 | visit_arguments = _clone |
|---|
| 866 | visit_keyword = _clone |
|---|
| 867 | visit_alias = _clone |
|---|
| 868 | |
|---|
| 869 | visit_Slice = _clone |
|---|
| 870 | visit_ExtSlice = _clone |
|---|
| 871 | visit_Index = _clone |
|---|
| 872 | |
|---|
| 873 | del _clone |
|---|