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