1 #!/usr/bin/env python 2 3 """ 4 Inspect source files, obtaining details of classes and attributes. 5 6 Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 21 -------- 22 23 The results of inspecting a module are as follows: 24 25 Constants 26 --------- 27 28 All constants identified within the code shall be registered. 29 30 Classes 31 ------- 32 33 All global classes shall be registered; local classes (within functions) or 34 nested classes (within classes) are not currently registered. 35 36 Base classes must be detected and constant. 37 38 All classes without bases are made to inherit from __builtins__.object in order 39 to support some standard methods. 40 41 Functions 42 --------- 43 44 All functions and lambda definitions shall be registered. 45 46 Namespaces 47 ---------- 48 49 Modules define their own "global" namespace, within which classes, functions 50 and lambda definitions establish a hierarchy of namespaces. 51 52 Only local, global and built-in namespaces are recognised; closures are not 53 supported. 54 55 Assignments 56 ----------- 57 58 Name assignment and attribute assignment involving modules and classes cause 59 names to be associated with values within namespaces. 60 61 Any assignments within loops are considered to cause the targets of such 62 assignments to provide non-constant values. 63 64 Assignments to names are only really considered to cause the targets of such 65 assignments to provide constant values if the targets reside in the module 66 namespace or in class namespaces, subject to the above conditions. 67 68 Assignments to names within functions are not generally considered to cause the 69 targets of such assignments to provide constant values since functions can be 70 invoked many times with different inputs. However, there may be benefits in 71 considering a local to be constant within a single invocation. 72 """ 73 74 from micropython.common import * 75 from micropython.data import * 76 import compiler.ast 77 from compiler.visitor import ASTVisitor 78 79 # Program visitors. 80 81 class InspectedModule(ASTVisitor, Module): 82 83 """ 84 An inspected module, providing core details via the Module superclass, but 85 capable of being used as an AST visitor. 86 """ 87 88 def __init__(self, name, importer): 89 90 """ 91 Initialise this visitor with a module 'name' and an 'importer' which is 92 used to provide access to other modules when required. 93 """ 94 95 ASTVisitor.__init__(self) 96 Module.__init__(self, name) 97 self.visitor = self 98 99 # Import machinery links. 100 101 self.importer = importer 102 self.optimisations = importer.optimisations 103 self.builtins = self.importer.modules.get("__builtins__") 104 self.loaded = 0 105 106 # Current expression state. 107 108 self.expr = None 109 110 # Namespace state. 111 112 self.in_init = 0 # Find instance attributes in __init__ methods. 113 self.in_method = 0 # Find instance attributes in all methods. 114 self.in_loop = 0 # Note loop "membership", affecting assignments. 115 self.namespaces = [] 116 self.module = None 117 self.functions = [] 118 119 def parse(self, filename): 120 121 "Parse the file having the given 'filename'." 122 123 module = compiler.parseFile(filename) 124 self.process(module) 125 126 def process(self, module): 127 128 "Process the given 'module'." 129 130 self.astnode = self.module = module 131 132 # Add __name__ to the namespace by adding an explicit assignment to the 133 # module. 134 135 module.node.nodes.insert(0, compiler.ast.Assign( 136 [compiler.ast.AssName("__name__", 0)], 137 compiler.ast.Const(self.full_name()) 138 )) 139 140 # First, visit module-level code, recording global names. 141 142 processed = self.dispatch(module) 143 144 # Then, for each function, detect and record globals declared in those 145 # functions. 146 147 for node, namespaces in self.functions: 148 self.process_globals(node) 149 150 self.finalise_namespace(self) 151 152 # Then, visit each function, recording other names. 153 154 for node, namespaces in self.functions: 155 self._visitFunctionBody(node, namespaces) 156 self.finalise_namespace(namespaces[-1]) 157 158 # Add references to other modules declared using the __all__ global. 159 160 if self.has_key("__all__"): 161 all = self["__all__"] 162 if isinstance(all, compiler.ast.List): 163 for n in all.nodes: 164 self.store(n.value, self.importer.add_module(self.name + "." + n.value)) 165 166 return processed 167 168 def process_globals(self, node): 169 170 """ 171 Within the given 'node', process global declarations, adjusting the 172 module namespace. 173 """ 174 175 for n in node.getChildNodes(): 176 if isinstance(n, compiler.ast.Global): 177 for name in n.names: 178 if not self.has_key(name): 179 self[name] = None 180 else: 181 self.process_globals(n) 182 183 def finalise_namespace(self, namespace): 184 185 "Finalise the given 'namespace'." 186 187 for names in namespace.get_all_attribute_usage(): 188 self.importer.use_names(names, namespace.full_name()) 189 for name in namespace.get_active_attributes(): 190 self.importer.use_specific_name(name, namespace.full_name()) 191 192 def vacuum(self): 193 194 """ 195 Vacuum the module namespace, removing unreferenced objects and unused 196 names. 197 """ 198 199 if self.should_optimise_unused_objects(): 200 self.vacuum_object(self) 201 202 all_objects = list(self.all_objects) 203 204 for obj in all_objects: 205 if isinstance(obj, Class): 206 self.vacuum_object(obj) 207 208 def vacuum_object(self, obj, delete_all=0): 209 210 "Vacuum the given object 'obj'." 211 212 for name, attr in obj.items(): 213 214 # Only consider deleting entire unused objects or things accessible 215 # via names which are never used. 216 217 if delete_all or not self.importer.uses_attribute(obj, name): 218 del obj[name] 219 220 # Delete any unambiguous attribute value. Such values can only 221 # have been defined within the object and therefore are not 222 # redefined by other code regions. 223 224 if attr.assignments == 1: 225 value = attr.get_value() 226 227 if value is not obj and value in self.all_objects: 228 self.all_objects.remove(value) 229 230 # Delete class contents. 231 232 if isinstance(value, Class): 233 self.vacuum_object(value, 1) 234 235 def finalise(self): 236 237 "Finalise the module." 238 239 for obj in self.all_objects: 240 if isinstance(obj, (Class, Function)): # NOTE: Perhaps not required. 241 obj.finalise_attributes(reset=1) 242 243 def add_object(self, obj, any_scope=0): 244 245 """ 246 Record 'obj' if non-local or if the optional 'any_scope' is set to a 247 true value. 248 """ 249 250 if any_scope or not (self.namespaces and isinstance(self.namespaces[-1], Function)): 251 self.all_objects.add(obj) 252 253 # Optimisation tests. 254 255 def should_optimise_unused_objects(self): 256 return "unused_objects" in self.optimisations 257 258 # Namespace methods. 259 260 def store(self, name, obj): 261 262 "Record attribute or local 'name', storing 'obj'." 263 264 if not self.namespaces: 265 self.set(name, obj, not self.in_loop) 266 else: 267 self.namespaces[-1].set(name, obj, not self.in_loop) 268 269 def store_lambda(self, obj): 270 271 "Store a lambda function 'obj'." 272 273 self.add_object(obj) 274 275 def store_module_attr(self, name, module): 276 277 """ 278 Record module attribute 'name' in the given 'module' using the current 279 expression. 280 """ 281 282 module.set(name, self.expr, 0) 283 284 def store_class_attr(self, name): 285 286 """ 287 Record class attribute 'name' in the current class using the current 288 expression. 289 """ 290 291 if self.in_method and self.namespaces[-2].has_key(name): 292 self.namespaces[-2].set(name, self.expr, 0) 293 return 1 294 295 return 0 296 297 def store_instance_attr(self, name): 298 299 "Record instance attribute 'name' in the current class." 300 301 if self.in_method: 302 303 # Current namespace is the function. 304 # Previous namespace is the class. 305 306 self.namespaces[-2].add_instance_attribute(name) 307 308 def get_namespace(self): 309 310 "Return the parent (or most recent) namespace currently exposed." 311 312 return (self.namespaces[-1:] or [self])[0] 313 314 def use_name(self, name): 315 316 "Use the given 'name' within the current namespace/unit." 317 318 unit = self.get_namespace() 319 self.importer.use_name(name, unit.full_name()) 320 321 # Attribute usage methods. 322 # These are convenience methods which refer to the specific namespace's 323 # implementation of these operations. 324 325 def new_branchpoint(self): 326 self.get_namespace()._new_branchpoint() 327 328 def new_branch(self): 329 self.get_namespace()._new_branch() 330 331 def shelve_branch(self): 332 self.get_namespace()._shelve_branch() 333 334 def merge_branches(self): 335 self.get_namespace()._merge_branches() 336 337 def define_attribute_user(self, node): 338 339 """ 340 Define 'node' as the user of attributes, indicating the point where the 341 user is defined. 342 """ 343 344 self.get_namespace()._define_attribute_user(node) 345 346 def reset_all_attributes(self): 347 self.get_namespace()._reset_all_attributes() 348 349 def use_attribute(self, name, attrname): 350 return self.get_namespace()._use_attribute(name, attrname) 351 352 # Visitor methods. 353 354 def default(self, node, *args): 355 raise InspectError(self.full_name(), node, "Node class %r is not supported." % node.__class__) 356 357 def dispatch(self, node, *args): 358 return ASTVisitor.dispatch(self, node, *args) 359 360 def NOP(self, node): 361 for n in node.getChildNodes(): 362 self.dispatch(n) 363 return None 364 365 def OP(self, node): 366 for n in node.getChildNodes(): 367 self.dispatch(n) 368 return Instance() 369 370 def _visitUnary(self, node): 371 372 "Accounting method for the unary operator 'node'." 373 374 method = unary_methods[node.__class__.__name__] 375 self.use_name(method) 376 return self.OP(node) 377 378 def _visitBinary(self, node): 379 380 "Accounting method for the binary operator 'node'." 381 382 left_method, right_method = binary_methods[node.__class__.__name__] 383 self.use_name(left_method) 384 self.use_name(right_method) 385 return self.OP(node) 386 387 def _visitFunction(self, node, name): 388 389 """ 390 Return a function object for the function defined by 'node' with the 391 given 'name'. If a lambda expression is being visited, 'name' should be 392 None. 393 """ 394 395 # Define the function object. 396 397 function = Function( 398 name, 399 self.get_namespace(), 400 node.argnames, 401 node.defaults, 402 (node.flags & 4 != 0), 403 (node.flags & 8 != 0), 404 self, 405 node 406 ) 407 408 self.add_object(function, any_scope=1) 409 410 # Make a back reference from the node for code generation. 411 412 node.unit = function 413 414 # Process the defaults. 415 416 for n in node.defaults: 417 self.expr = self.dispatch(n) 418 function.store_default(self.expr) 419 420 self.functions.append((node, self.namespaces + [function])) 421 422 if name is not None: 423 self.store(name, function) 424 else: 425 self.store_lambda(function) 426 427 # Where defaults exist, an instance needs creating. Thus, it makes 428 # no sense to return a reference to the function here, since the 429 # recipient will not be referencing the function itself. 430 431 if node.defaults: 432 return Instance() # indicates no known target 433 434 return function 435 436 def _visitFunctionBody(self, node, namespaces): 437 438 "Enter the function." 439 440 # Current namespace is the function. 441 # Previous namespace is the class. 442 443 if len(namespaces) > 1 and isinstance(namespaces[-2], Class): 444 if namespaces[-1].name == "__init__": 445 self.in_init = 1 446 self.in_method = 1 447 448 self.namespaces = namespaces 449 self.dispatch(node.code) 450 451 self.in_init = 0 452 self.in_method = 0 453 454 # Specific handler methods. 455 456 visitAdd = _visitBinary 457 458 visitAnd = OP 459 460 visitAssert = NOP 461 462 def visitAssign(self, node): 463 self.expr = self.dispatch(node.expr) 464 for n in node.nodes: 465 self.dispatch(n) 466 return None 467 468 def visitAssAttr(self, node): 469 expr = self.dispatch(node.expr) 470 471 # Record the attribute on the presumed target. 472 473 if isinstance(expr, Attr): 474 if expr.name == "self": 475 if not self.store_class_attr(node.attrname): 476 self.store_instance_attr(node.attrname) 477 elif isinstance(expr.get_value(), Module): 478 self.store_module_attr(node.attrname, expr.get_value()) 479 print "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.get_value().name) 480 481 # Note usage of the attribute. 482 483 if expr.parent is self.get_namespace(): 484 node._attrnames = self.use_attribute(expr.name, node.attrname) 485 486 return None 487 488 def visitAssList(self, node): 489 490 # Declare names which will be used by generated code. 491 492 self.use_name("__getitem__") 493 494 # Process the assignment. 495 496 for i, n in enumerate(node.nodes): 497 self.dispatch(n) 498 self.importer.make_constant(i) # for __getitem__(i) at run-time 499 return None 500 501 def visitAssName(self, node): 502 if node.flags == "OP_DELETE": 503 raise InspectError(self.full_name(), node, "Deletion of attribute %r is not supported." % node.name) 504 505 self.store(node.name, self.expr) 506 self.define_attribute_user(node) 507 self.use_attribute(None, node.name) # ensure the presence of the given name 508 return None 509 510 visitAssTuple = visitAssList 511 512 def visitAugAssign(self, node): 513 514 # Accounting. 515 516 aug_method, (left_method, right_method) = augassign_methods[node.op] 517 self.use_name(aug_method) 518 self.use_name(left_method) 519 self.use_name(right_method) 520 521 # Process the assignment. 522 523 self.expr = self.dispatch(node.expr) 524 525 # NOTE: Similar to micropython.ast handler code. 526 # NOTE: Slices and subscripts not supported. 527 528 if isinstance(node.node, compiler.ast.Name): 529 self.visitAssName(node.node) 530 elif isinstance(node.node, compiler.ast.Getattr): 531 self.visitAssAttr(node.node) 532 else: 533 raise InspectError(self.full_name(), node, "AugAssign(Slice or Subscript)") 534 535 return None 536 537 visitBackquote = OP 538 539 visitBitand = _visitBinary 540 541 visitBitor = _visitBinary 542 543 visitBitxor = _visitBinary 544 545 def visitBreak(self, node): 546 self.reset_all_attributes() 547 548 visitCallFunc = OP 549 550 def visitClass(self, node): 551 552 """ 553 Register the class at the given 'node' subject to the restrictions 554 mentioned in the module docstring. 555 """ 556 557 if self.namespaces: 558 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 559 return None 560 else: 561 cls = Class(node.name, self.get_namespace(), self, node) 562 563 # Visit the base class expressions, attempting to find concrete 564 # definitions of classes. 565 566 for base in node.bases: 567 expr = self.dispatch(base) 568 if isinstance(expr, Attr): 569 if expr.assignments != 1: 570 raise InspectError(self.full_name(), node, 571 "Base class %r for %r is not constant." % (base, cls.full_name())) 572 else: 573 cls.add_base(expr.get_value()) 574 else: # if expr is None: 575 raise InspectError(self.full_name(), node, 576 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 577 578 # NOTE: Potentially dubious measure to permit __init__ availability. 579 # If no bases exist, adopt the 'object' class. 580 581 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 582 expr = self.dispatch(compiler.ast.Name("object")) 583 cls.add_base(expr.get_value()) 584 585 # Make a back reference from the node for code generation. 586 587 node.unit = cls 588 589 # Make an entry for the class. 590 591 self.store(node.name, cls) 592 self.add_object(cls) 593 594 # Process the class body. 595 596 self.namespaces.append(cls) 597 self.dispatch(node.code) 598 self.finalise_namespace(cls) 599 self.namespaces.pop() 600 601 return cls 602 603 def visitCompare(self, node): 604 605 # Accounting. 606 # NOTE: Replicates some code in micropython.ast.visitCompare. 607 608 for op in node.ops: 609 op_name, next_node = op 610 methods = comparison_methods[op_name] 611 if methods is not None: 612 self.use_name(methods[0]) 613 self.use_name(methods[1]) 614 elif op_name.endswith("in"): 615 self.use_name("__contains__") 616 617 return self.OP(node) 618 619 def visitConst(self, node): 620 621 # Register the constant, if necessary, returning the resulting object. 622 623 self.use_name(self.importer.get_constant_type_name(node.value)) 624 return self.importer.make_constant(node.value) 625 626 def visitContinue(self, node): 627 self.reset_all_attributes() 628 629 visitDecorators = NOP 630 631 visitDict = OP 632 633 visitDiscard = NOP 634 635 visitDiv = _visitBinary 636 637 visitEllipsis = NOP 638 639 visitExec = NOP 640 641 visitExpression = OP 642 643 visitFloorDiv = _visitBinary 644 645 def visitFor(self, node): 646 self.new_branchpoint() 647 648 # Declare names which will be used by generated code. 649 650 self.use_name("__iter__") 651 self.use_name("next") 652 653 self.dispatch(node.assign) 654 self.dispatch(node.list) 655 656 # Enter the loop. 657 # Propagate attribute usage to branches. 658 659 self.in_loop = 1 660 self.new_branch() 661 self.dispatch(node.body) 662 self.shelve_branch() 663 self.in_loop = 0 664 665 # Maintain a branch for the else clause or the current retained usage 666 # where execution avoids the conditional clauses. 667 668 self.new_branch() 669 if node.else_ is not None: 670 self.dispatch(node.else_) 671 self.shelve_branch() 672 673 self.merge_branches() 674 return None 675 676 def visitFrom(self, node): 677 module = self.importer.load(node.modname, 1) 678 679 #if module is None: 680 # print "Warning:", node.modname, "not imported." 681 682 for name, alias in node.names: 683 if name != "*": 684 if module is not None and module.namespace.has_key(name): 685 attr = module[name] 686 self.store(alias or name, attr) 687 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: 688 self.importer.load(attr.get_value().name) 689 690 # Support the import of names from missing modules. 691 692 else: 693 self.store(alias or name, UnresolvedName(name, node.modname, self)) 694 else: 695 if module is not None: 696 for n in module.namespace.keys(): 697 attr = module[n] 698 self.store(n, attr) 699 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: 700 self.importer.load(attr.get_value().name) 701 702 return None 703 704 def visitFunction(self, node): 705 return self._visitFunction(node, node.name) 706 707 visitGenExpr = OP 708 709 visitGenExprFor = NOP 710 711 visitGenExprIf = NOP 712 713 visitGenExprInner = NOP 714 715 def visitGetattr(self, node): 716 expr = self.dispatch(node.expr) 717 attrname = node.attrname 718 719 # Attempt to identify the nature of the attribute. 720 721 if isinstance(expr, Attr): 722 value = expr.get_value() 723 if isinstance(value, (Class, Module)): 724 attr = value.namespace.get(attrname) 725 elif isinstance(value, UnresolvedName): 726 attr = UnresolvedName(attrname, value.full_name(), self) 727 else: 728 attr = None 729 730 # Note usage of the attribute. 731 732 if expr.parent is self.get_namespace(): 733 node._attrnames = self.use_attribute(expr.name, attrname) 734 else: 735 self.use_name(attrname) 736 737 elif self.builtins is not None: 738 attr = self.builtins.get(attrname) 739 self.use_name(attrname) 740 741 else: 742 attr = UnresolvedName(attrname, value.full_name(), self) 743 self.use_name(attrname) 744 745 return attr 746 747 def visitGlobal(self, node): 748 if self.namespaces: 749 for name in node.names: 750 ns = self.namespaces[-1] 751 if not ns.make_global(name): 752 raise InspectError(ns.full_name(), node, "Name %r is global and local in %r" % (name, ns.full_name())) 753 754 # The name is recorded in an earlier process. 755 756 def visitIf(self, node): 757 self.new_branchpoint() 758 759 # Propagate attribute usage to branches. 760 761 for test, body in node.tests: 762 self.dispatch(test) 763 764 self.new_branch() 765 self.dispatch(body) 766 self.shelve_branch() 767 768 # Maintain a branch for the else clause or the current retained usage 769 # where execution avoids the conditional clauses. 770 771 self.new_branch() 772 if node.else_ is not None: 773 self.dispatch(node.else_) 774 self.shelve_branch() 775 776 self.merge_branches() 777 return None 778 779 visitIfExp = NOP 780 781 def visitImport(self, node): 782 for name, alias in node.names: 783 if alias is not None: 784 module = self.importer.load(name, 1) or UnresolvedName(None, name, self) 785 self.store(alias, module) 786 else: 787 module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self) 788 self.store(name.split(".")[0], module) 789 790 return None 791 792 visitInvert = _visitUnary 793 794 def visitKeyword(self, node): 795 self.dispatch(node.expr) 796 self.importer.make_constant(node.name) 797 self.keyword_names.add(node.name) 798 return None 799 800 def visitLambda(self, node): 801 self.use_name(None) # lambda functions have no names but are assumed to be invoked 802 return self._visitFunction(node, None) 803 804 visitLeftShift = _visitBinary 805 806 visitList = OP 807 808 visitListComp = OP 809 810 visitListCompFor = NOP 811 812 visitListCompIf = NOP 813 814 visitMod = _visitBinary 815 816 def visitModule(self, node): 817 818 # Make a back reference from the node for code generation. 819 820 node.unit = self 821 return self.dispatch(node.node) 822 823 visitMul = _visitBinary 824 825 def visitName(self, node): 826 name = node.name 827 828 # Constants. 829 830 if self.importer.predefined_constants.has_key(name): 831 attr = self.importer.get_predefined_constant(name) 832 833 # Locals. 834 835 elif self.namespaces and self.namespaces[-1].has_key(name): 836 attr = self.namespaces[-1][name] 837 838 # Note usage of the local (potentially a class attribute). 839 840 node._attrnames = self.use_attribute(None, name) 841 842 # Globals. 843 844 elif self.has_key(name): 845 attr = self[name] 846 847 # Note usage of the module attribute. 848 849 node._attrnames = self.use_attribute(None, name) 850 851 # Builtins. 852 853 elif self.builtins is not None and self.builtins.has_key(name): 854 attr = self.builtins[name] 855 856 # Note usage of the module attribute. 857 858 node._attrnames = self.builtins.use_attribute(None, name) 859 860 # Unknown. 861 862 else: 863 attr = None 864 self.use_name(name) 865 866 return attr 867 868 visitNot = OP 869 870 visitOr = OP 871 872 visitPass = NOP 873 874 visitPower = _visitBinary 875 876 visitPrint = NOP 877 878 visitPrintnl = NOP 879 880 visitRaise = NOP 881 882 visitReturn = NOP 883 884 visitRightShift = _visitBinary 885 886 visitSlice = OP 887 888 visitSliceobj = OP 889 890 def visitStmt(self, node): 891 for n in node.nodes: 892 self.dispatch(n) 893 return None 894 895 visitSub = _visitBinary 896 897 def visitSubscript(self, node): 898 self.use_name("__getitem__") 899 self.OP(node) 900 901 def visitTryExcept(self, node): 902 self.dispatch(node.body) 903 904 self.new_branchpoint() 905 906 for name, var, n in node.handlers: 907 self.new_branch() 908 909 # Establish the local for the handler. 910 911 if var is not None: 912 self.dispatch(var) 913 if n is not None: 914 self.dispatch(n) 915 916 self.shelve_branch() 917 918 if node.else_ is not None: 919 self.new_branch() 920 self.dispatch(node.else_) 921 self.shelve_branch() 922 923 self.merge_branches() 924 return None 925 926 visitTryFinally = NOP 927 928 visitTuple = OP 929 930 visitUnaryAdd = _visitUnary 931 932 visitUnarySub = _visitUnary 933 934 def visitWhile(self, node): 935 self.new_branchpoint() 936 937 # Propagate attribute usage to branches. 938 939 self.in_loop = 1 940 self.dispatch(node.test) 941 self.new_branch() 942 self.dispatch(node.body) 943 self.shelve_branch() 944 self.in_loop = 0 945 946 # Maintain a branch for the else clause or the current retained usage 947 # where execution avoids the conditional clauses. 948 949 self.new_branch() 950 if node.else_ is not None: 951 self.dispatch(node.else_) 952 self.shelve_branch() 953 954 self.merge_branches() 955 return None 956 957 visitWith = NOP 958 959 visitYield = NOP 960 961 # vim: tabstop=4 expandtab shiftwidth=4