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