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