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, 2011, 2012 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 from micropython.errors import * 78 import compiler.ast 79 import sys 80 81 # Program visitors. 82 83 class InspectedModule(ASTVisitor, Module): 84 85 """ 86 An inspected module, providing core details via the Module superclass, but 87 capable of being used as an AST visitor. 88 """ 89 90 def __init__(self, name, importer): 91 92 """ 93 Initialise this visitor with a module 'name' and an 'importer' which is 94 used to provide access to other modules when required. 95 """ 96 97 Module.__init__(self, name, importer) 98 self.visitor = self 99 100 # Import machinery links. 101 102 self.optimisations = self.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 self.in_assignment = 0 # For slice and subscript handling. 110 111 # Namespace state. 112 113 self.in_method = 0 # Find instance attributes in all methods. 114 self.in_function = 0 # Note function presence, affecting definitions. 115 self.in_loop = 0 # Note loop "membership", affecting assignments. 116 self.namespaces = [] 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 """ 129 Process the given 'module', visiting only module-level code and only 130 extracting global declarations from functions. In order to support 131 deferred imports, the function code is processed separately after all 132 modules have been initially processed. 133 """ 134 135 self.astnode = module 136 137 # Add __name__ to the namespace. 138 139 self.store("__name__", self._visitConst(self.full_name())) 140 141 # First, visit module-level code, recording global names. 142 143 processed = self.dispatch(module) 144 145 # Then, for each function, detect and record globals declared in those 146 # functions. 147 148 for node, namespaces in self.functions: 149 self.process_globals(node) 150 151 self.finalise_attribute_usage() 152 153 # Add references to other modules declared using the __all__ global. 154 155 if self.has_key("__all__"): 156 all = self["__all__"] 157 if isinstance(all, compiler.ast.List): 158 for n in all.nodes: 159 self.store(n.value, self.importer.add_module(self.name + "." + n.value)) 160 161 return processed 162 163 def process_functions(self): 164 165 """ 166 Process all function bodies. Deferred imports may occur during this 167 process. 168 """ 169 170 # Then, visit each function, recording other names. This happens to 171 # work for lambda definitions inside functions since they are added to 172 # the end of self.functions and are thus visited as the iteration 173 # reaches the end of the original list. 174 175 for node, namespaces in self.functions: 176 self._visitFunctionBody(node, namespaces) 177 namespaces[-1].finalise_attribute_usage() 178 179 def process_globals(self, node): 180 181 """ 182 Within the given 'node', process global declarations, adjusting the 183 module namespace. 184 """ 185 186 for n in node.getChildNodes(): 187 if isinstance(n, compiler.ast.Global): 188 for name in n.names: 189 if not self.has_key(name): 190 self[name] = make_instance() 191 else: 192 self.process_globals(n) 193 194 def vacuum(self): 195 196 """ 197 Vacuum the module namespace, removing unreferenced objects and unused 198 names. 199 """ 200 201 if self.should_optimise_unused_objects(): 202 self.vacuum_object(self) 203 204 all_objects = list(self.all_objects) 205 206 for obj in all_objects: 207 self.vacuum_object(obj) 208 209 def vacuum_object(self, obj, delete_all=0): 210 211 "Vacuum the given object 'obj'." 212 213 # Get all constant objects in apparent use. 214 215 if delete_all: 216 obj_objects = set() 217 else: 218 obj_objects = [] 219 for name, attr in obj.items_for_vacuum(): 220 221 # Get constant objects for attributes in use. 222 223 if self.importer.uses_attribute(obj.full_name(), name) and \ 224 attr is not None and attr.is_constant(): 225 226 value = attr.get_value() 227 obj_objects.append(value) 228 229 # Now vacuum unused attributes and objects not in use. 230 231 for name, attr in obj.items_for_vacuum(): 232 233 # Only consider deleting entire unused objects or things accessible 234 # via names which are never used. 235 236 if delete_all or not self.importer.uses_attribute(obj.full_name(), name): 237 obj.vacuum_item(name) 238 239 # Delete any unambiguous attribute value. Such values can only 240 # have been defined within the object and therefore are not 241 # redefined by other code regions. 242 243 if attr is not None and attr.is_constant(): 244 value = attr.get_value() 245 246 # The value must have this object as a parent. 247 # However, it must not be shared by several names. 248 249 if value is not obj and value.parent is obj and \ 250 value in self.all_objects and value not in obj_objects: 251 252 self.all_objects.remove(value) 253 254 # Delete class contents and lambdas from functions. 255 256 self.vacuum_object(value, 1) 257 258 def unfinalise(self): 259 260 "Reset finalised information for the module." 261 262 for obj in self.all_objects: 263 obj.unfinalise_attributes() 264 265 def finalise(self, objtable): 266 267 "Finalise the module." 268 269 for obj in self.all_objects: 270 obj.finalise(objtable) 271 272 self.finalise_users(objtable) 273 274 def add_object(self, obj, any_scope=0): 275 276 """ 277 Record 'obj' if non-local or if the optional 'any_scope' is set to a 278 true value. 279 """ 280 281 if any_scope or not (self.namespaces and isinstance(self.namespaces[-1], Function)): 282 self.all_objects.add(obj) 283 284 # Optimisation tests. 285 286 def should_optimise_unused_objects(self): 287 return "unused_objects" in self.optimisations 288 289 # Namespace methods. 290 291 def in_class(self, namespaces=None): 292 namespaces = namespaces or self.namespaces 293 return len(namespaces) > 1 and isinstance(namespaces[-2], Class) 294 295 def store(self, name, obj): 296 297 "Record attribute or local 'name', storing 'obj'." 298 299 # Store in the module. 300 301 if not self.namespaces: 302 if self.in_loop and self.used_in_scope(name, "builtins"): 303 raise InspectError("Name %r already used as a built-in." % name) 304 else: 305 self.set(name, obj, not self.in_loop) 306 307 # Or store locally. 308 309 else: 310 locals = self.namespaces[-1] 311 312 if self.in_loop and locals.used_in_scope(name, "global") and not name in locals.globals: 313 raise InspectError("Name %r already used as global." % name) 314 elif self.in_loop and locals.used_in_scope(name, "builtins"): 315 raise InspectError("Name %r already used as a built-in." % name) 316 else: 317 locals.set(name, obj, not self.in_loop) 318 319 def store_lambda(self, obj): 320 321 "Store a lambda function 'obj'." 322 323 self.add_object(obj) 324 self.get_namespace().add_lambda(obj) 325 326 def store_module_attr(self, name, module): 327 328 """ 329 Record module attribute 'name' in the given 'module' using the current 330 expression. 331 """ 332 333 module.set(name, self.expr, 0) 334 self.use_specific_attribute(module.full_name(), name) 335 336 def store_class_attr(self, name, cls): 337 338 """ 339 Record class attribute 'name' in the given class 'cls' using the current 340 expression. 341 """ 342 343 cls.set(name, self.expr, 0) 344 self.use_specific_attribute(cls.full_name(), name) 345 346 def store_instance_attr(self, name, tentative=False): 347 348 """ 349 Record instance attribute 'name' in the current class. If 'tentative' is 350 set to a true value, the instance attribute will be discarded if a class 351 attribute is observed. 352 """ 353 354 if self.in_method: 355 356 # Current namespace is the function. 357 # Previous namespace is the class. 358 359 cls = self.namespaces[-2] 360 cls.add_instance_attribute(name, tentative) 361 362 # NOTE: The instance attribute, although defined in a specific 363 # NOTE: class, obviously appears in all descendant classes. 364 365 self.use_specific_attribute(cls.full_name(), name) 366 367 def get_namespace(self): 368 369 "Return the parent (or most recent) namespace currently exposed." 370 371 return (self.namespaces[-1:] or [self])[0] 372 373 def use_name(self, name, node=None, value=None): 374 375 """ 376 Use the given 'name' within the current namespace/unit, either in 377 conjunction with a particular object (if 'node' is specified and not 378 None) or unconditionally. 379 """ 380 381 if node is not None and isinstance(node, compiler.ast.Name): 382 self.use_attribute(node.name, name, value) 383 384 # For general name usage, declare usage of the given name from this 385 # particular unit. 386 387 else: 388 unit = self.get_namespace() 389 self.importer.use_name(name, unit.full_name(), value) 390 391 def use_constant(self, const): 392 393 "Use the given 'const' within the current namespace/unit." 394 395 unit = self.get_namespace() 396 self.importer.use_constant(const, unit.full_name()) 397 398 # Attribute usage methods. 399 # These are convenience methods which refer to the specific namespace's 400 # implementation of these operations. 401 402 def new_branchpoint(self, loop_node=None): 403 self.get_namespace()._new_branchpoint(loop_node) 404 405 def new_branch(self, node): 406 self.get_namespace()._new_branch(node) 407 408 def abandon_branch(self): 409 self.get_namespace()._abandon_branch() 410 411 def suspend_broken_branch(self): 412 self.get_namespace()._suspend_broken_branch() 413 414 def suspend_continuing_branch(self): 415 self.get_namespace()._suspend_continuing_branch() 416 417 def shelve_branch(self): 418 self.get_namespace()._shelve_branch() 419 420 def merge_branches(self): 421 self.get_namespace()._merge_branches() 422 423 def resume_broken_branches(self): 424 self.get_namespace()._resume_broken_branches() 425 426 def resume_continuing_branches(self): 427 self.get_namespace()._resume_continuing_branches() 428 429 def resume_abandoned_branches(self): 430 self.get_namespace()._resume_abandoned_branches() 431 432 def define_attribute_user(self, node): 433 434 """ 435 Define 'node' as the user of attributes, indicating the point where the 436 user is defined. 437 """ 438 439 self.get_namespace()._define_attribute_user(node) 440 441 def use_attribute(self, name, attrname, value=None): 442 443 """ 444 Note usage on the attribute user 'name' of the attribute 'attrname', 445 noting an assignment if 'value' is specified. 446 """ 447 448 return self.get_namespace()._use_attribute(name, attrname, value) 449 450 def use_specific_attribute(self, objname, attrname, from_name=None): 451 452 """ 453 Note usage on the object having the given 'objname' of the attribute 454 'attrname'. If 'objname' is None, the current namespace is chosen as the 455 object providing the attribute. 456 """ 457 458 return self.get_namespace()._use_specific_attribute(objname, attrname, from_name) 459 460 # Visitor methods. 461 462 def default(self, node, *args): 463 raise InspectError("Node class %r is not supported." % node.__class__) 464 465 def NOP(self, node): 466 for n in node.getChildNodes(): 467 self.dispatch(n) 468 469 def NOP_ABANDON(self, node): 470 self.NOP(node) 471 self.abandon_branch() 472 473 def TEST_NOP(self, node): 474 self.use_name("__bool__", node) 475 self.NOP(node) 476 477 def OP(self, node): 478 for n in node.getChildNodes(): 479 self.dispatch(n) 480 return make_instance() 481 482 def TEST_OP(self, node): 483 self.use_name("__bool__", node) 484 self.new_branchpoint() 485 486 # Propagate attribute usage to branches. 487 # Each node starts a new conditional region, effectively making a deeply 488 # nested collection of if-like statements. 489 490 for n in node.nodes: 491 self.new_branch(n) 492 self.dispatch(n) 493 494 # The nested regions must be terminated. 495 496 for n in node.nodes: 497 self.shelve_branch() 498 499 self.merge_branches() 500 return make_instance() 501 502 # Generic support for classes of operations. 503 504 def _ensureOperators(self): 505 attr, scope, namespace = self._get_with_scope("$operator") 506 if attr is None: 507 module = self.importer.load("operator") 508 self["$operator"] = module 509 else: 510 module = attr.get_value() 511 return module 512 513 def _visitOperator(self, node, operator_name=None): 514 515 "Accounting method for the operator 'node'." 516 517 operator_module = self._ensureOperators() 518 operator_fn = operator_functions[operator_name or node.__class__.__name__] 519 self.use_specific_attribute(operator_module.full_name(), operator_fn) 520 return self.OP(node) 521 522 _visitBinary = \ 523 _visitUnary = _visitOperator 524 525 def _visitAttr(self, expr, attrname, node): 526 527 """ 528 Process the attribute provided by the given 'expr' with the given 529 'attrname' and involving the given 'node'. 530 """ 531 532 # Attempt to identify the nature of the attribute. 533 534 if isinstance(expr, Attr): 535 value = expr.get_value() 536 537 # Get the attribute and record its usage. 538 539 if isinstance(value, (Class, Module)): 540 541 # Check for class.__class__. 542 543 if attrname == "__class__" and isinstance(value, Class): 544 attr = type_class 545 else: 546 attr = value.get(attrname) or make_instance() 547 self.use_specific_attribute(value.full_name(), attrname) 548 549 elif isinstance(value, UnresolvedName): 550 attr = UnresolvedName(attrname, value.full_name(), self) 551 552 # The actual attribute is not readily identifiable and is assumed 553 # to be an instance. 554 555 else: 556 557 # Record any instance attributes. 558 559 if expr.name == "self": 560 self.store_instance_attr(attrname, tentative=True) 561 562 attr = make_instance() 563 564 # Note usage of the attribute where a local is involved. 565 566 self._visitAttrUser(expr, attrname, node) 567 568 # No particular attribute has been identified, thus a general instance 569 # is assumed. 570 571 else: 572 attr = make_instance() 573 self.use_name(attrname, node) 574 575 return attr 576 577 def _visitAttrUser(self, expr, attrname, node, value=None): 578 579 """ 580 Note usage of the attribute provided by 'expr' with the given 'attrname' 581 where a local is involved, annotating the given 'node'. If the optional 582 'value' is given, note an assignment for future effects on attributes 583 where such attributes are inferred from the usage. 584 """ 585 586 # Access to attribute via a local in functions or classes but not 587 # modules (since module-level locals are globals that can be modified 588 # independently of the namespace). 589 590 if expr.parent is self.get_namespace() and not self.get_namespace() is self: 591 592 # NOTE: Revisiting of nodes may occur for loops. 593 594 if not hasattr(node, "_attrusers"): 595 node._attrusers = set() 596 597 node._attrusers.update(self.use_attribute(expr.name, attrname, value)) 598 node._username = expr.name 599 else: 600 self.use_name(attrname, node.expr, value) 601 602 def _visitConst(self, value): 603 604 """ 605 Register the constant given by 'value', if necessary, returning the 606 resulting object. The type name is noted as being used, thus preserving 607 the class in any generated program. 608 """ 609 610 self.use_specific_attribute("__builtins__", self.importer.get_constant_type_name(value)) 611 const = self.importer.make_constant(value) 612 self.use_constant(const) 613 return const 614 615 def _visitFunction(self, node, name): 616 617 """ 618 Return a function object for the function defined by 'node' with the 619 given 'name'. If a lambda expression is being visited, 'name' should be 620 None. 621 """ 622 623 # Define the function object. 624 625 function = Function( 626 name, 627 self.get_namespace(), 628 node.argnames, 629 node.defaults, 630 (node.flags & 4 != 0), 631 (node.flags & 8 != 0), 632 self.in_loop or self.in_function, 633 self, 634 node 635 ) 636 637 self.add_object(function, any_scope=1) 638 639 # Make a back reference from the node for code generation. 640 641 node.unit = function 642 643 # Process the defaults. 644 645 for n in node.defaults: 646 self.expr = self.dispatch(n) 647 function.store_default(self.expr) 648 649 # Note attribute usage where tuple parameters are involved. 650 651 if function.tuple_parameters(): 652 self.use_name("__getitem__", node) 653 654 # Record the namespace context of the function for later processing. 655 656 self.functions.append((node, self.namespaces + [function])) 657 658 # Store the function. 659 660 if name is not None: 661 self.store(name, function) 662 else: 663 self.store_lambda(function) 664 665 # Test the defaults and assess whether an dynamic object will result. 666 667 function.make_dynamic() 668 return function 669 670 def _visitFunctionBody(self, node, namespaces): 671 672 "Enter the function." 673 674 # Current namespace is the function. 675 # Previous namespace is the class. 676 677 if self.in_class(namespaces): 678 self.in_method = 1 679 680 in_function = self.in_function 681 in_loop = self.in_loop 682 self.in_function = 1 683 self.in_loop = 0 684 685 self.namespaces = namespaces 686 self.dispatch(node.code) 687 688 self.in_loop = in_loop 689 self.in_function = in_function 690 self.in_method = 0 691 692 # Specific handler methods. 693 694 visitAdd = _visitBinary 695 696 visitAnd = TEST_OP 697 698 visitAssert = NOP 699 700 def visitAssign(self, node): 701 self.expr = self.dispatch(node.expr) 702 self.in_assignment = 1 703 for n in node.nodes: 704 self.dispatch(n) 705 self.in_assignment = 0 706 707 def visitAssAttr(self, node): 708 expr = self.dispatch(node.expr) 709 attrname = node.attrname 710 711 # Record the attribute on the presumed target. 712 713 if isinstance(expr, Attr): 714 value = expr.get_value() 715 716 if expr.name == "self": 717 self.store_instance_attr(attrname) 718 self.use_attribute(expr.name, attrname, value) # NOTE: Impose constraints on the type given the hierarchy. 719 self._visitAttrUser(expr, attrname, node, self.expr) 720 721 elif isinstance(value, Module): 722 self.store_module_attr(attrname, value) 723 print >>sys.stderr, "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.get_value().name) 724 725 elif isinstance(value, Class): 726 self.store_class_attr(attrname, value) 727 728 # Note usage of the attribute where a local is involved. 729 730 else: 731 self._visitAttrUser(expr, attrname, node, self.expr) 732 733 else: 734 self.use_name(attrname, node) 735 736 def visitAssList(self, node): 737 738 # Declare names which will be used by generated code. 739 740 self.use_name("__getitem__", node) 741 742 # Process the assignment. 743 744 for i, n in enumerate(node.nodes): 745 self.dispatch(n) 746 self._visitConst(i) # for __getitem__(i) at run-time 747 748 def visitAssName(self, node): 749 if hasattr(node, "flags") and node.flags == "OP_DELETE": 750 print >>sys.stderr, "Warning: deletion of attribute %r in %r is not supported." % (node.name, self.full_name()) 751 #raise InspectError("Deletion of attribute %r is not supported." % node.name) 752 753 self.store(node.name, self.expr) 754 self.define_attribute_user(node) 755 756 # Ensure the presence of the given name in this namespace. 757 # NOTE: Consider not registering assignments involving methods, since 758 # NOTE: this is merely creating aliases for such methods. 759 760 if isinstance(self.get_namespace(), (Class, Module)): 761 if not isinstance(self.expr, Attr) or not isinstance(self.expr.get_value(), Function): 762 self.use_specific_attribute(None, node.name) 763 else: 764 fn = self.expr.get_value() 765 ns = self.get_namespace().full_name() 766 self.use_specific_attribute(fn.parent.full_name(), fn.name, "%s.%s" % (ns, node.name)) 767 768 visitAssTuple = visitAssList 769 770 def visitAugAssign(self, node): 771 772 # Accounting. 773 774 operator_fn = operator_functions.get(node.op) 775 operator_module = self._ensureOperators() 776 self.use_specific_attribute(operator_module.full_name(), operator_fn) 777 778 # Process the assignment. 779 780 self.expr = self.dispatch(node.expr) 781 782 # NOTE: Similar to micropython.ast handler code. 783 # NOTE: Slices and subscripts are supported by __setitem__(slice) and 784 # NOTE: not __setslice__. 785 786 if isinstance(node.node, compiler.ast.Name): 787 self.visitAssName(node.node) 788 elif isinstance(node.node, compiler.ast.Getattr): 789 self.visitAssAttr(node.node) 790 else: 791 self.use_specific_attribute("__builtins__", "slice") 792 self.use_name("__setitem__", node) 793 794 visitBackquote = OP 795 796 visitBitand = _visitBinary 797 798 visitBitor = _visitBinary 799 800 visitBitxor = _visitBinary 801 802 def visitBreak(self, node): 803 self.NOP(node) 804 self.suspend_broken_branch() 805 806 visitCallFunc = OP 807 808 def visitClass(self, node): 809 810 """ 811 Register the class at the given 'node' subject to the restrictions 812 mentioned in the module docstring. 813 """ 814 815 if self.namespaces: 816 print >>sys.stderr, "Warning: class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 817 return 818 else: 819 if self.in_loop: 820 print >>sys.stderr, "Warning: class %r in %r defined in a loop." % (node.name, self.full_name()) 821 822 cls = get_class(node.name, self.get_namespace(), self, node) 823 824 # Make a back reference from the node for code generation. 825 826 node.unit = cls 827 828 # Process base classes in the context of the class's namespace. 829 # This confines references to such classes to the class instead of 830 # the namespace in which it is defined. 831 832 self.namespaces.append(cls) 833 834 # Visit the base class expressions, attempting to find concrete 835 # definitions of classes. 836 837 for base in node.bases: 838 expr = self.dispatch(base) 839 840 # Each base class must be constant and known at compile-time. 841 842 if isinstance(expr, Attr): 843 if expr.assignments != 1: 844 raise InspectError("Base class %r for %r is not constant: %r" % (base, cls.full_name(), expr)) 845 elif not isinstance(expr.get_value(), Class): 846 raise InspectError("Base class %r for %r is not a class: %r" % (base, cls.full_name(), expr.get_value())) 847 else: 848 cls.add_base(expr.get_value()) 849 850 # Where no expression value is available, the base class is 851 # not identifiable. 852 853 else: 854 raise InspectError("Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 855 856 # NOTE: Potentially dubious measure to permit __init__ availability. 857 # If no bases exist, adopt the 'object' class. 858 859 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 860 expr = self.dispatch(compiler.ast.Name("object")) 861 cls.add_base(expr.get_value()) 862 863 # Make an entry for the class in the parent namespace. 864 865 self.namespaces.pop() 866 self.store(node.name, cls) 867 self.add_object(cls) 868 869 # Process the class body in its own namespace. 870 # Add __name__ to the namespace. 871 872 self.namespaces.append(cls) 873 self.store("__name__", self._visitConst(node.name)) 874 self.dispatch(node.code) 875 self.namespaces.pop() 876 877 cls.finalise_attribute_usage() 878 return cls 879 880 def visitCompare(self, node): 881 882 # Accounting. 883 # NOTE: Replicates some code in micropython.ast.visitCompare. 884 885 self.use_name("__bool__", node) 886 887 this_node = node 888 889 for op in node.ops: 890 op_name, next_node = op 891 892 # Define name/attribute usage. 893 # Get the applicable operation. 894 895 operator_fn = operator_functions.get(op_name) 896 897 # For operators, reference the specific function involved. 898 899 if operator_fn is not None: 900 operator_module = self._ensureOperators() 901 self.use_specific_attribute(operator_module.full_name(), operator_fn) 902 903 # Define __contains__ usage on the next node. 904 905 elif op_name.endswith("in"): 906 self.use_name("__contains__", next_node) 907 908 this_node = next_node 909 910 return self.OP(node) 911 912 def visitConst(self, node): 913 return self._visitConst(node.value) 914 915 def visitContinue(self, node): 916 self.NOP(node) 917 self.suspend_continuing_branch() 918 919 visitDecorators = NOP 920 921 visitDict = OP 922 923 visitDiscard = NOP 924 925 visitDiv = _visitBinary 926 927 visitEllipsis = NOP 928 929 visitExec = NOP 930 931 visitExpression = OP 932 933 visitFloorDiv = _visitBinary 934 935 def visitFor(self, node): 936 self.new_branchpoint(node) 937 938 # Declare names which will be used by generated code. 939 940 self.use_name("__iter__", node.list) 941 self.use_name("next") 942 self.use_name("StopIteration") 943 944 in_loop = self.in_loop 945 self.in_loop = 1 946 self.dispatch(node.list) 947 948 # NOTE: Could generate AST nodes for the actual operations instead of 949 # NOTE: manually generating code in micropython.ast. 950 951 self.expr = make_instance() # each element is a result of a function call 952 self.dispatch(node.assign) 953 954 # Enter the loop. 955 # Propagate attribute usage to branches. 956 957 self.new_branch(node) 958 self.dispatch(node.body) 959 960 self.resume_continuing_branches() 961 962 self.shelve_branch() 963 964 self.in_loop = in_loop 965 966 # A null branch is used to record a path around the loop. 967 968 self.new_branch(node.else_ or NullBranch()) 969 self.shelve_branch() 970 971 self.merge_branches() 972 973 # The else clause is evaluated outside any branch. 974 975 if node.else_ is not None: 976 self.dispatch(node.else_) 977 978 # Any suspended branches from the loop can now be resumed. 979 980 self.resume_broken_branches() 981 982 def visitFrom(self, node): 983 module = self.importer.load(node.modname, 1) 984 if module and not module.loaded: 985 print >>sys.stderr, "Warning: a circular import of %s is being attempted in %s" % (node.modname, self.full_name()) 986 987 #if module is None: 988 # print >>sys.stderr, "Warning:", node.modname, "not imported." 989 990 for name, alias in node.names: 991 if name != "*": 992 if module: 993 994 # Missing names may refer to submodules. 995 996 if not module.has_key(name): 997 submodule = self.importer.load(node.modname + "." + name, 1) 998 if submodule: 999 if not submodule.loaded: 1000 print >>sys.stderr, "Warning: a circular import of %s.%s is being attempted in %s" % ( 1001 node.modname, name, self.full_name()) 1002 1003 module.store(name, submodule) 1004 1005 # Complete the import if the name was found. 1006 1007 if module.has_key(name): 1008 attr = module[name] 1009 self.store(alias or name, attr) 1010 self.use_specific_attribute(module.full_name(), name) 1011 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: 1012 self.importer.load(attr.get_value().name) 1013 continue 1014 1015 # Support the import of names from missing modules. 1016 1017 self.store(alias or name, UnresolvedName(name, node.modname, self)) 1018 1019 else: 1020 if module: 1021 for n in module.keys(): 1022 attr = module[n] 1023 self.store(n, attr) 1024 self.use_specific_attribute(module.full_name(), n) 1025 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: 1026 self.importer.load(attr.get_value().name) 1027 1028 def visitFunction(self, node): 1029 return self._visitFunction(node, node.name) 1030 1031 visitGenExpr = OP 1032 1033 visitGenExprFor = NOP 1034 1035 visitGenExprIf = NOP 1036 1037 visitGenExprInner = NOP 1038 1039 def visitGetattr(self, node): 1040 expr = self.dispatch(node.expr) 1041 attrname = node.attrname 1042 return self._visitAttr(expr, attrname, node) 1043 1044 def visitGlobal(self, node): 1045 if self.namespaces: 1046 for name in node.names: 1047 ns = self.namespaces[-1] 1048 if not ns.make_global(name): 1049 raise InspectError("Name %r is global and local in %r" % (name, ns.full_name())) 1050 1051 # The name is recorded in an earlier process. 1052 1053 def visitIf(self, node): 1054 self.use_name("__bool__", node) 1055 self.new_branchpoint() 1056 1057 # Propagate attribute usage to branches. 1058 1059 for test, body in node.tests: 1060 self.dispatch(test) 1061 1062 self.new_branch(body) 1063 self.dispatch(body) 1064 self.shelve_branch() 1065 1066 # Maintain a branch for the else clause. 1067 1068 self.new_branch(node.else_ or NullBranch()) 1069 if node.else_ is not None: 1070 self.dispatch(node.else_) 1071 self.shelve_branch() 1072 1073 self.merge_branches() 1074 1075 def visitIfExp(self, node): 1076 self.use_name("__bool__", node) 1077 self.new_branchpoint() 1078 1079 # Propagate attribute usage to branches. 1080 1081 self.dispatch(node.test) 1082 1083 self.new_branch(node.then) 1084 self.dispatch(node.then) 1085 self.shelve_branch() 1086 1087 self.new_branch(node.else_) 1088 self.dispatch(node.else_) 1089 self.shelve_branch() 1090 1091 self.merge_branches() 1092 return make_instance() # either outcome is possible 1093 1094 def visitImport(self, node): 1095 for name, alias in node.names: 1096 if alias is not None: 1097 module = self.importer.load(name, 1) or UnresolvedName(None, name, self) 1098 self.store(alias, module) 1099 else: 1100 module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self) 1101 self.store(name.split(".")[0], module) 1102 1103 visitInvert = _visitUnary 1104 1105 def visitKeyword(self, node): 1106 self.dispatch(node.expr) 1107 self._visitConst(node.name) 1108 self.keyword_names.add(node.name) 1109 1110 def visitLambda(self, node): 1111 fn = self._visitFunction(node, None) 1112 self.use_specific_attribute(None, fn.name) 1113 return fn 1114 1115 visitLeftShift = _visitBinary 1116 1117 def visitList(self, node): 1118 self.use_specific_attribute("__builtins__", "list") 1119 return self.OP(node) 1120 1121 def visitListComp(self, node): 1122 1123 # Note that explicit dispatch is performed. 1124 1125 if node.quals: 1126 self.visitListCompFor(node.quals[0], node.quals[1:], node.expr) 1127 return make_instance() 1128 1129 def visitListCompFor(self, node, following_quals, expr): 1130 self.new_branchpoint() 1131 1132 # Declare names which will be used by generated code. 1133 1134 self.use_name("__iter__", node.list) 1135 self.use_name("next") 1136 1137 in_loop = self.in_loop 1138 self.in_loop = 1 1139 self.dispatch(node.list) 1140 1141 # NOTE: Could generate AST nodes for the actual operations instead of 1142 # NOTE: manually generating code in micropython.ast. 1143 1144 self.expr = make_instance() # each element is a result of a function call 1145 self.dispatch(node.assign) 1146 1147 # Enter the loop. 1148 # Propagate attribute usage to branches. 1149 1150 self.new_branch(node) 1151 1152 # Note that explicit dispatch is performed. 1153 1154 if node.ifs: 1155 self.visitListCompIf(node.ifs[0], node.ifs[1:], following_quals, expr) 1156 elif following_quals: 1157 self.visitListCompFor(following_quals[0], following_quals[1:], expr) 1158 else: 1159 self.dispatch(expr) 1160 1161 self.shelve_branch() 1162 self.in_loop = in_loop 1163 1164 self.merge_branches() 1165 1166 def visitListCompIf(self, node, following_ifs, following_quals, expr): 1167 self.use_name("__bool__", node) 1168 self.new_branchpoint() 1169 1170 # Propagate attribute usage to branches. 1171 1172 self.dispatch(node.test) 1173 1174 # Note that explicit dispatch is performed. 1175 1176 if following_ifs: 1177 self.visitListCompIf(following_ifs[0], following_ifs[1:], following_quals, expr) 1178 elif following_quals: 1179 self.visitListCompFor(following_quals[0], following_quals[1:], expr) 1180 else: 1181 self.new_branch(expr) 1182 self.dispatch(expr) 1183 self.shelve_branch() 1184 1185 # Maintain a branch for the else clause. 1186 1187 self.new_branch(NullBranch()) 1188 self.shelve_branch() 1189 1190 self.merge_branches() 1191 1192 visitMod = _visitBinary 1193 1194 def visitModule(self, node): 1195 1196 # Make a back reference from the node for code generation. 1197 1198 node.unit = self 1199 return self.dispatch(node.node) 1200 1201 visitMul = _visitBinary 1202 1203 def visitName(self, node): 1204 return self.get_namespace().get_using_node(node.name, node) or make_instance() 1205 1206 def visitNot(self, node): 1207 self.use_name("__bool__", node) 1208 self.dispatch(node.expr) 1209 return make_instance() 1210 1211 visitOr = TEST_OP 1212 1213 visitPass = NOP 1214 1215 visitPower = _visitBinary 1216 1217 def _visitPrint(self, node, function_name): 1218 self.NOP(node) 1219 self.use_specific_attribute("__builtins__", function_name) 1220 1221 def visitPrint(self, node): 1222 self._visitPrint(node, "_print") 1223 1224 def visitPrintnl(self, node): 1225 self._visitPrint(node, "_printnl") 1226 1227 visitRaise = NOP_ABANDON 1228 1229 visitReturn = NOP_ABANDON 1230 1231 visitRightShift = _visitBinary 1232 1233 def visitSlice(self, node): 1234 return self._visitOperator(node, self.in_assignment and "AssSlice" or "Slice") 1235 1236 visitSliceobj = OP 1237 1238 def visitStmt(self, node): 1239 for n in node.nodes: 1240 self.dispatch(n) 1241 1242 visitSub = _visitBinary 1243 1244 def visitSubscript(self, node): 1245 return self._visitOperator(node, self.in_assignment and "AssSubscript" or "Subscript") 1246 1247 def visitTryExcept(self, node): 1248 self.new_branchpoint() 1249 self.dispatch(node.body) 1250 1251 for name, var, n in node.handlers: 1252 self.new_branch(n) 1253 1254 # Any abandoned branches from the body can now be resumed. 1255 1256 self.resume_abandoned_branches() 1257 1258 # Establish the local for the handler. 1259 1260 if var is not None: 1261 self.dispatch(var) 1262 if n is not None: 1263 self.dispatch(n) 1264 1265 self.shelve_branch() 1266 1267 # The else clause maintains the usage from the body but without the 1268 # abandoned branches since they would never lead to the else clause 1269 # being executed. 1270 1271 self.new_branch(node.else_ or NullBranch()) 1272 if node.else_ is not None: 1273 self.dispatch(node.else_) 1274 self.shelve_branch() 1275 1276 self.merge_branches() 1277 1278 visitTryFinally = NOP 1279 1280 visitTuple = OP 1281 1282 visitUnaryAdd = _visitUnary 1283 1284 visitUnarySub = _visitUnary 1285 1286 def visitWhile(self, node): 1287 self.use_name("__bool__", node) 1288 self.new_branchpoint(node) 1289 1290 # Propagate attribute usage to branches. 1291 1292 in_loop = self.in_loop 1293 self.in_loop = 1 1294 1295 # The test is evaluated initially and again in the loop. 1296 1297 self.dispatch(node.test) 1298 1299 self.new_branch(node) 1300 self.dispatch(node.body) 1301 1302 self.resume_continuing_branches() 1303 1304 self.dispatch(node.test) 1305 self.shelve_branch() 1306 1307 self.in_loop = in_loop 1308 1309 # A null branch is used to record a path around the loop. 1310 1311 self.new_branch(node.else_ or NullBranch()) 1312 self.shelve_branch() 1313 1314 self.merge_branches() 1315 1316 # The else clause is evaluated outside any branch. 1317 1318 if node.else_ is not None: 1319 self.dispatch(node.else_) 1320 1321 # Any suspended branches from the loop can now be resumed. 1322 1323 self.resume_broken_branches() 1324 1325 visitWith = NOP 1326 1327 visitYield = NOP 1328 1329 # vim: tabstop=4 expandtab shiftwidth=4