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