1 #!/usr/bin/env python 2 3 """ 4 Inspect source files, obtaining details of classes and attributes. 5 6 Copyright (C) 2007, 2008, 2009, 2010 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. This affects particularly the 71 definition of functions or lambdas within functions. However, there may be 72 benefits in considering a local to be constant within a single invocation. 73 """ 74 75 from micropython.common import * 76 from micropython.data import * 77 import compiler.ast 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, importer) 97 self.visitor = self 98 99 # Import machinery links. 100 101 self.optimisations = self.importer.optimisations 102 self.builtins = self.importer.modules.get("__builtins__") 103 self.loaded = 0 104 105 # Current expression state. 106 107 self.expr = None 108 109 # Namespace state. 110 111 self.in_init = 0 # Find instance attributes in __init__ methods. 112 self.in_method = 0 # Find instance attributes in all methods. 113 self.in_function = 0 # Note function presence, affecting definitions. 114 self.in_loop = 0 # Note loop "membership", affecting assignments. 115 self.namespaces = [] 116 self.functions = [] 117 118 def parse(self, filename): 119 120 "Parse the file having the given 'filename'." 121 122 module = compiler.parseFile(filename) 123 self.process(module) 124 125 def process(self, module): 126 127 "Process the given 'module'." 128 129 self.astnode = module 130 131 # Add __name__ to the namespace by adding an explicit assignment to the 132 # module. 133 134 module.node.nodes.insert(0, compiler.ast.Assign( 135 [compiler.ast.AssName("__name__", 0)], 136 compiler.ast.Const(self.full_name()) 137 )) 138 139 # First, visit module-level code, recording global names. 140 141 processed = self.dispatch(module) 142 143 # Then, for each function, detect and record globals declared in those 144 # functions. 145 146 for node, namespaces in self.functions: 147 self.process_globals(node) 148 149 self.finalise_attribute_usage() 150 151 # Then, visit each function, recording other names. 152 153 for node, namespaces in self.functions: 154 self._visitFunctionBody(node, namespaces) 155 namespaces[-1].finalise_attribute_usage() 156 157 # Add references to other modules declared using the __all__ global. 158 159 if self.has_key("__all__"): 160 all = self["__all__"] 161 if isinstance(all, compiler.ast.List): 162 for n in all.nodes: 163 self.store(n.value, self.importer.add_module(self.name + "." + n.value)) 164 165 return processed 166 167 def process_globals(self, node): 168 169 """ 170 Within the given 'node', process global declarations, adjusting the 171 module namespace. 172 """ 173 174 for n in node.getChildNodes(): 175 if isinstance(n, compiler.ast.Global): 176 for name in n.names: 177 if not self.has_key(name): 178 self[name] = None 179 else: 180 self.process_globals(n) 181 182 def vacuum(self): 183 184 """ 185 Vacuum the module namespace, removing unreferenced objects and unused 186 names. 187 """ 188 189 if self.should_optimise_unused_objects(): 190 self.vacuum_object(self) 191 192 all_objects = list(self.all_objects) 193 194 for obj in all_objects: 195 self.vacuum_object(obj) 196 197 def vacuum_object(self, obj, delete_all=0): 198 199 "Vacuum the given object 'obj'." 200 201 for name, attr in obj.items_for_vacuum(): 202 203 # Only consider deleting entire unused objects or things accessible 204 # via names which are never used. 205 206 if delete_all or not self.importer.uses_attribute(obj.full_name(), name): 207 obj.vacuum_item(name) 208 209 # Delete any unambiguous attribute value. Such values can only 210 # have been defined within the object and therefore are not 211 # redefined by other code regions. 212 213 if attr.assignments == 1: 214 value = attr.get_value() 215 216 if value is not obj and value in self.all_objects: 217 self.all_objects.remove(value) 218 219 # Delete class contents and lambdas from functions. 220 221 self.vacuum_object(value, 1) 222 223 def unfinalise(self): 224 225 "Reset finalised information for the module." 226 227 for obj in self.all_objects: 228 obj.unfinalise_attributes() 229 230 def finalise(self): 231 232 "Finalise the module." 233 234 for obj in self.all_objects: 235 obj.finalise_attributes() 236 237 def add_object(self, obj, any_scope=0): 238 239 """ 240 Record 'obj' if non-local or if the optional 'any_scope' is set to a 241 true value. 242 """ 243 244 if any_scope or not (self.namespaces and isinstance(self.namespaces[-1], Function)): 245 self.all_objects.add(obj) 246 247 # Optimisation tests. 248 249 def should_optimise_unused_objects(self): 250 return "unused_objects" in self.optimisations 251 252 # Namespace methods. 253 254 def in_class(self, namespaces=None): 255 namespaces = namespaces or self.namespaces 256 return len(namespaces) > 1 and isinstance(namespaces[-2], Class) 257 258 def store(self, name, obj): 259 260 "Record attribute or local 'name', storing 'obj'." 261 262 # Store in the module. 263 264 if not self.namespaces: 265 if self.in_loop and self.used_in_scope(name, "builtins"): 266 raise InspectError("Name %r already used as a built-in." % name) 267 else: 268 self.set(name, obj, not self.in_loop) 269 270 # Or store locally. 271 272 else: 273 locals = self.namespaces[-1] 274 275 if self.in_loop and locals.used_in_scope(name, "global") and not name in locals.globals: 276 raise InspectError("Name %r already used as global." % name) 277 elif self.in_loop and locals.used_in_scope(name, "builtins"): 278 raise InspectError("Name %r already used as a built-in." % name) 279 else: 280 locals.set(name, obj, not self.in_loop) 281 282 def store_lambda(self, obj): 283 284 "Store a lambda function 'obj'." 285 286 self.add_object(obj) 287 self.get_namespace().add_lambda(obj) 288 289 def store_module_attr(self, name, module): 290 291 """ 292 Record module attribute 'name' in the given 'module' using the current 293 expression. 294 """ 295 296 module.set(name, self.expr, 0) 297 298 def store_class_attr(self, name): 299 300 """ 301 Record class attribute 'name' in the current class using the current 302 expression. 303 """ 304 305 if self.in_method and self.namespaces[-2].has_key(name): 306 self.namespaces[-2].set(name, self.expr, 0) 307 return 1 308 309 return 0 310 311 def store_instance_attr(self, name): 312 313 "Record instance attribute 'name' in the current class." 314 315 if self.in_method: 316 317 # Current namespace is the function. 318 # Previous namespace is the class. 319 320 self.namespaces[-2].add_instance_attribute(name) 321 322 def get_namespace(self): 323 324 "Return the parent (or most recent) namespace currently exposed." 325 326 return (self.namespaces[-1:] or [self])[0] 327 328 def use_name(self, name, node=None): 329 330 """ 331 Use the given 'name' within the current namespace/unit, either in 332 conjunction with a particular object (if 'node' is specified and not 333 None) or unconditionally. 334 """ 335 336 if node is not None and isinstance(node, compiler.ast.Name): 337 self.use_attribute(node.name, name) 338 339 # For general name usage, declare usage of the given name from this 340 # particular unit. 341 342 else: 343 unit = self.get_namespace() 344 self.importer.use_name(name, unit.full_name()) 345 346 # Attribute usage methods. 347 # These are convenience methods which refer to the specific namespace's 348 # implementation of these operations. 349 350 def new_branchpoint(self): 351 self.get_namespace()._new_branchpoint() 352 353 def new_branch(self, loop_node=None): 354 self.get_namespace()._new_branch(loop_node) 355 356 def abandon_branch(self): 357 self.get_namespace()._abandon_branch() 358 359 def shelve_branch(self): 360 self.get_namespace()._shelve_branch() 361 362 def merge_branches(self): 363 self.get_namespace()._merge_branches() 364 365 def define_attribute_user(self, node): 366 367 """ 368 Define 'node' as the user of attributes, indicating the point where the 369 user is defined. 370 """ 371 372 self.get_namespace()._define_attribute_user(node) 373 374 def use_attribute(self, name, attrname): 375 376 "Note usage on the attribute user 'name' of the attribute 'attrname'." 377 378 return self.get_namespace()._use_attribute(name, attrname) 379 380 def use_specific_attribute(self, objname, attrname): 381 382 """ 383 Note usage on the object having the given 'objname' of the attribute 384 'attrname'. If 'objname' is None, the current namespace is chosen as the 385 object providing the attribute. 386 """ 387 388 return self.get_namespace()._use_specific_attribute(objname, attrname) 389 390 # Visitor methods. 391 392 def default(self, node, *args): 393 raise InspectError("Node class %r is not supported." % node.__class__) 394 395 def NOP(self, node): 396 for n in node.getChildNodes(): 397 self.dispatch(n) 398 return None 399 400 def NOP_ABANDON(self, node): 401 self.NOP(node) 402 self.abandon_branch() 403 404 def OP(self, node): 405 for n in node.getChildNodes(): 406 self.dispatch(n) 407 return Instance() 408 409 # Generic support for classes of operations. 410 411 def _visitUnary(self, node): 412 413 "Accounting method for the unary operator 'node'." 414 415 method = unary_methods[node.__class__.__name__] 416 self.use_name(method, node) 417 return self.OP(node) 418 419 def _visitBinary(self, node): 420 421 "Accounting method for the binary operator 'node'." 422 423 left_method, right_method = binary_methods[node.__class__.__name__] 424 self.use_name(left_method, node) 425 self.use_name(right_method, node) 426 return self.OP(node) 427 428 def _visitFunction(self, node, name): 429 430 """ 431 Return a function object for the function defined by 'node' with the 432 given 'name'. If a lambda expression is being visited, 'name' should be 433 None. 434 """ 435 436 # Define the function object. 437 438 function = Function( 439 name, 440 self.get_namespace(), 441 node.argnames, 442 node.defaults, 443 (node.flags & 4 != 0), 444 (node.flags & 8 != 0), 445 self.in_loop or self.in_function, 446 self, 447 node 448 ) 449 450 self.add_object(function, any_scope=1) 451 452 # Make a back reference from the node for code generation. 453 454 node.unit = function 455 456 # Process the defaults. 457 458 for n in node.defaults: 459 self.expr = self.dispatch(n) 460 function.store_default(self.expr) 461 462 self.functions.append((node, self.namespaces + [function])) 463 464 # Store the function. 465 466 if name is not None: 467 self.store(name, function) 468 else: 469 self.store_lambda(function) 470 471 # Test the defaults and assess whether an dynamic object will result. 472 473 function.make_dynamic() 474 return function 475 476 def _visitFunctionBody(self, node, namespaces): 477 478 "Enter the function." 479 480 # Current namespace is the function. 481 # Previous namespace is the class. 482 483 if self.in_class(namespaces): 484 if namespaces[-1].name == "__init__": 485 self.in_init = 1 486 self.in_method = 1 487 488 in_function = self.in_function 489 in_loop = self.in_loop 490 self.in_function = 1 491 self.in_loop = 0 492 493 self.namespaces = namespaces 494 self.dispatch(node.code) 495 496 self.in_loop = in_loop 497 self.in_function = in_function 498 self.in_init = 0 499 self.in_method = 0 500 501 # Specific handler methods. 502 503 visitAdd = _visitBinary 504 505 visitAnd = OP 506 507 visitAssert = NOP 508 509 def visitAssign(self, node): 510 self.expr = self.dispatch(node.expr) 511 for n in node.nodes: 512 self.dispatch(n) 513 return None 514 515 def visitAssAttr(self, node): 516 expr = self.dispatch(node.expr) 517 518 # Record the attribute on the presumed target. 519 520 if isinstance(expr, Attr): 521 if expr.name == "self": 522 if not self.store_class_attr(node.attrname): 523 self.store_instance_attr(node.attrname) 524 elif isinstance(expr.get_value(), Module): 525 self.store_module_attr(node.attrname, expr.get_value()) 526 print "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.get_value().name) 527 528 # Note usage of the attribute where a local is involved. 529 530 if expr.parent is self.get_namespace(): 531 node._attrusers = self.use_attribute(expr.name, node.attrname) 532 node._username = expr.name 533 534 return None 535 536 def visitAssList(self, node): 537 538 # Declare names which will be used by generated code. 539 540 self.use_name("__getitem__", node) 541 542 # Process the assignment. 543 544 for i, n in enumerate(node.nodes): 545 self.dispatch(n) 546 self.importer.make_constant(i) # for __getitem__(i) at run-time 547 return None 548 549 def visitAssName(self, node): 550 if hasattr(node, "flags") and node.flags == "OP_DELETE": 551 print "Warning: deletion of attribute %r in %r is not supported." % (node.name, self.full_name()) 552 #raise InspectError("Deletion of attribute %r is not supported." % node.name) 553 554 self.store(node.name, self.expr) 555 self.define_attribute_user(node) 556 557 # Ensure the presence of the given name in this namespace. 558 559 self.use_specific_attribute(None, node.name) 560 return None 561 562 visitAssTuple = visitAssList 563 564 def visitAugAssign(self, node): 565 566 # Accounting. 567 568 aug_method, (left_method, right_method) = augassign_methods[node.op] 569 self.use_name(aug_method, node) 570 self.use_name(left_method, node) 571 self.use_name(right_method, node) 572 573 # Process the assignment. 574 575 self.expr = self.dispatch(node.expr) 576 577 # NOTE: Similar to micropython.ast handler code. 578 # NOTE: Slices and subscripts not supported. 579 580 if isinstance(node.node, compiler.ast.Name): 581 self.visitAssName(node.node) 582 elif isinstance(node.node, compiler.ast.Getattr): 583 self.visitAssAttr(node.node) 584 else: 585 raise InspectError("AugAssign(Slice or Subscript)") 586 587 return None 588 589 visitBackquote = OP 590 591 visitBitand = _visitBinary 592 593 visitBitor = _visitBinary 594 595 visitBitxor = _visitBinary 596 597 visitBreak = NOP_ABANDON 598 599 visitCallFunc = OP 600 601 def visitClass(self, node): 602 603 """ 604 Register the class at the given 'node' subject to the restrictions 605 mentioned in the module docstring. 606 """ 607 608 if self.namespaces: 609 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 610 return None 611 else: 612 if self.in_loop: 613 print "Warning: class %r in %r defined in a loop." % (node.name, self.full_name()) 614 615 cls = Class(node.name, self.get_namespace(), self, node) 616 617 # Make a back reference from the node for code generation. 618 619 node.unit = cls 620 621 # Process base classes in the context of the class's namespace. 622 # This confines references to such classes to the class instead of 623 # the namespace in which it is defined. 624 625 self.namespaces.append(cls) 626 627 # Visit the base class expressions, attempting to find concrete 628 # definitions of classes. 629 630 for base in node.bases: 631 expr = self.dispatch(base) 632 633 # Each base class must be constant and known at compile-time. 634 635 if isinstance(expr, Attr): 636 if expr.assignments != 1: 637 raise InspectError("Base class %r for %r is not constant." % (base, cls.full_name())) 638 else: 639 cls.add_base(expr.get_value()) 640 641 # Where no expression value is available, the base class is 642 # not identifiable. 643 644 else: 645 raise InspectError("Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 646 647 # NOTE: Potentially dubious measure to permit __init__ availability. 648 # If no bases exist, adopt the 'object' class. 649 650 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 651 expr = self.dispatch(compiler.ast.Name("object")) 652 cls.add_base(expr.get_value()) 653 654 # Make an entry for the class in the parent namespace. 655 656 self.namespaces.pop() 657 self.store(node.name, cls) 658 self.add_object(cls) 659 660 # Process the class body in its own namespace. 661 662 self.namespaces.append(cls) 663 self.dispatch(node.code) 664 self.namespaces.pop() 665 666 cls.finalise_attribute_usage() 667 return cls 668 669 def visitCompare(self, node): 670 671 # Accounting. 672 # NOTE: Replicates some code in micropython.ast.visitCompare. 673 674 this_node = node 675 676 for op in node.ops: 677 op_name, next_node = op 678 679 # Get the applicable methods. 680 681 methods = comparison_methods[op_name] 682 683 # Define name/attribute usage. 684 685 if methods is not None: 686 self.use_name(methods[0], this_node) 687 self.use_name(methods[1], next_node) 688 elif op_name.endswith("in"): 689 self.use_name("__contains__", next_node) 690 691 this_node = next_node 692 693 return self.OP(node) 694 695 def visitConst(self, node): 696 697 # Register the constant, if necessary, returning the resulting object. 698 699 self.use_name(self.importer.get_constant_type_name(node.value), node) 700 return self.importer.make_constant(node.value) 701 702 visitContinue = NOP_ABANDON 703 704 visitDecorators = NOP 705 706 visitDict = OP 707 708 visitDiscard = NOP 709 710 visitDiv = _visitBinary 711 712 visitEllipsis = NOP 713 714 visitExec = NOP 715 716 visitExpression = OP 717 718 visitFloorDiv = _visitBinary 719 720 def visitFor(self, node): 721 self.new_branchpoint() 722 723 # Declare names which will be used by generated code. 724 725 self.use_name("__iter__", node.list) 726 self.use_name("next") 727 self.use_name("StopIteration") 728 729 in_loop = self.in_loop 730 self.in_loop = 1 731 self.dispatch(node.list) 732 self.dispatch(node.assign) 733 734 # Enter the loop. 735 # Propagate attribute usage to branches. 736 737 self.new_branch() 738 self.dispatch(node.body) 739 self.shelve_branch() 740 self.in_loop = in_loop 741 742 # Maintain a branch for the else clause or the current retained usage 743 # where execution avoids the conditional clauses. 744 745 self.new_branch() 746 if node.else_ is not None: 747 self.dispatch(node.else_) 748 self.shelve_branch() 749 750 self.merge_branches() 751 return None 752 753 def visitFrom(self, node): 754 module = self.importer.load(node.modname, 1) 755 756 #if module is None: 757 # print "Warning:", node.modname, "not imported." 758 759 for name, alias in node.names: 760 if name != "*": 761 if module is not None and module.has_key(name): 762 attr = module[name] 763 self.store(alias or name, attr) 764 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: 765 self.importer.load(attr.get_value().name) 766 767 # Support the import of names from missing modules. 768 769 else: 770 self.store(alias or name, UnresolvedName(name, node.modname, self)) 771 else: 772 if module is not None: 773 for n in module.keys(): 774 attr = module[n] 775 self.store(n, attr) 776 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: 777 self.importer.load(attr.get_value().name) 778 779 return None 780 781 def visitFunction(self, node): 782 return self._visitFunction(node, node.name) 783 784 visitGenExpr = OP 785 786 visitGenExprFor = NOP 787 788 visitGenExprIf = NOP 789 790 visitGenExprInner = NOP 791 792 def visitGetattr(self, node): 793 expr = self.dispatch(node.expr) 794 attrname = node.attrname 795 796 # Attempt to identify the nature of the attribute. 797 798 if isinstance(expr, Attr): 799 value = expr.get_value() 800 801 # Get the attribute and record its usage. 802 803 if isinstance(value, (Class, Module)): 804 attr = value.get(attrname) 805 self.use_specific_attribute(value.full_name(), attrname) 806 807 elif isinstance(value, UnresolvedName): 808 attr = UnresolvedName(attrname, value.full_name(), self) 809 810 else: 811 attr = None 812 813 # Note usage of the attribute where a local is involved. 814 815 if expr.parent is self.get_namespace(): 816 node._attrusers = self.use_attribute(expr.name, attrname) 817 node._username = expr.name 818 else: 819 self.use_name(attrname, node.expr) 820 821 elif self.builtins is not None: 822 attr = self.builtins.get(attrname) 823 self.use_specific_attribute(self.builtins.full_name(), attrname) 824 825 else: 826 attr = UnresolvedName(attrname, value.full_name(), self) 827 828 return attr 829 830 def visitGlobal(self, node): 831 if self.namespaces: 832 for name in node.names: 833 ns = self.namespaces[-1] 834 if not ns.make_global(name): 835 raise InspectError("Name %r is global and local in %r" % (name, ns.full_name())) 836 837 # The name is recorded in an earlier process. 838 839 def visitIf(self, node): 840 self.new_branchpoint() 841 842 # Propagate attribute usage to branches. 843 844 for test, body in node.tests: 845 self.dispatch(test) 846 847 self.new_branch() 848 self.dispatch(body) 849 self.shelve_branch() 850 851 # Maintain a branch for the else clause or the current retained usage 852 # where execution avoids the conditional clauses. 853 854 self.new_branch() 855 if node.else_ is not None: 856 self.dispatch(node.else_) 857 self.shelve_branch() 858 859 self.merge_branches() 860 return None 861 862 visitIfExp = NOP 863 864 def visitImport(self, node): 865 for name, alias in node.names: 866 if alias is not None: 867 module = self.importer.load(name, 1) or UnresolvedName(None, name, self) 868 self.store(alias, module) 869 else: 870 module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self) 871 self.store(name.split(".")[0], module) 872 873 return None 874 875 visitInvert = _visitUnary 876 877 def visitKeyword(self, node): 878 self.dispatch(node.expr) 879 self.importer.make_constant(node.name) 880 self.keyword_names.add(node.name) 881 return None 882 883 def visitLambda(self, node): 884 fn = self._visitFunction(node, None) 885 self.use_specific_attribute(None, fn.name) 886 return fn 887 888 visitLeftShift = _visitBinary 889 890 def visitList(self, node): 891 self.use_specific_attribute("__builtins__", "list") 892 self.OP(node) 893 894 def visitListComp(self, node): 895 for qual in node.quals: 896 self.dispatch(qual) 897 self.dispatch(node.expr) 898 899 def visitListCompFor(self, node): 900 self.new_branchpoint() 901 902 # Declare names which will be used by generated code. 903 904 self.use_name("__iter__", node.list) 905 self.use_name("next") 906 907 in_loop = self.in_loop 908 self.in_loop = 1 909 self.dispatch(node.list) 910 self.dispatch(node.assign) 911 912 # Enter the loop. 913 # Propagate attribute usage to branches. 914 915 self.new_branch() 916 917 for if_ in node.ifs: 918 self.dispatch(if_) 919 920 self.shelve_branch() 921 self.in_loop = in_loop 922 923 self.merge_branches() 924 return None 925 926 visitListCompIf = NOP 927 928 visitMod = _visitBinary 929 930 def visitModule(self, node): 931 932 # Make a back reference from the node for code generation. 933 934 node.unit = self 935 return self.dispatch(node.node) 936 937 visitMul = _visitBinary 938 939 def visitName(self, node): 940 return self.get_namespace().get_using_node(node.name, node) 941 942 visitNot = OP 943 944 visitOr = OP 945 946 visitPass = NOP 947 948 visitPower = _visitBinary 949 950 visitPrint = NOP 951 952 visitPrintnl = NOP 953 954 visitRaise = NOP_ABANDON 955 956 visitReturn = NOP_ABANDON 957 958 visitRightShift = _visitBinary 959 960 def visitSlice(self, node): 961 self.use_specific_attribute("__builtins__", "slice") 962 self.use_name("__getitem__", node) 963 self.OP(node) 964 965 visitSliceobj = OP 966 967 def visitStmt(self, node): 968 for n in node.nodes: 969 self.dispatch(n) 970 return None 971 972 visitSub = _visitBinary 973 974 def visitSubscript(self, node): 975 self.use_name("__getitem__", node) 976 self.OP(node) 977 978 def visitTryExcept(self, node): 979 self.dispatch(node.body) 980 981 self.new_branchpoint() 982 983 for name, var, n in node.handlers: 984 self.new_branch() 985 986 # Establish the local for the handler. 987 988 if var is not None: 989 self.dispatch(var) 990 if n is not None: 991 self.dispatch(n) 992 993 self.shelve_branch() 994 995 if node.else_ is not None: 996 self.new_branch() 997 self.dispatch(node.else_) 998 self.shelve_branch() 999 1000 self.merge_branches() 1001 return None 1002 1003 visitTryFinally = NOP 1004 1005 visitTuple = OP 1006 1007 visitUnaryAdd = _visitUnary 1008 1009 visitUnarySub = _visitUnary 1010 1011 def visitWhile(self, node): 1012 self.new_branchpoint() 1013 1014 # Propagate attribute usage to branches. 1015 1016 in_loop = self.in_loop 1017 self.in_loop = 1 1018 self.dispatch(node.test) 1019 self.new_branch(node) 1020 self.dispatch(node.body) 1021 self.shelve_branch() 1022 self.in_loop = in_loop 1023 1024 # Maintain a branch for the else clause or the current retained usage 1025 # where execution avoids the conditional clauses. 1026 # NOTE: Consider merging here before the else clause. 1027 1028 self.new_branch() 1029 if node.else_ is not None: 1030 self.dispatch(node.else_) 1031 self.shelve_branch() 1032 1033 self.merge_branches() 1034 return None 1035 1036 visitWith = NOP 1037 1038 visitYield = NOP 1039 1040 # vim: tabstop=4 expandtab shiftwidth=4