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