1 #!/usr/bin/env python 2 3 """ 4 Annotate program node structures. The code in this module operates upon nodes 5 which are produced when simplifying AST node trees originating from the compiler 6 module. 7 8 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 9 10 This software is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License as 12 published by the Free Software Foundation; either version 2 of 13 the License, or (at your option) any later version. 14 15 This software is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public 21 License along with this library; see the file LICENCE.txt 22 If not, write to the Free Software Foundation, Inc., 23 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 24 25 -------- 26 27 To use this module, the easiest approach is to use the load function: 28 29 load(filename, builtins) 30 31 To control module importing, an importer should be constructed and employed. 32 Here, the standard path for module searching is used: 33 34 importer = Importer(sys.path) 35 load(filename, builtins, importer) 36 37 Underneath the load function, the annotate function provides support for 38 annotating modules already processed by simplify and fixnames: 39 40 annotate(module, builtins) 41 42 And at the most basic level, the most intricate approach involves obtaining an 43 Annotator object: 44 45 annotator = Annotator() 46 47 Then, processing an existing module with it: 48 49 annotator.process(module) 50 51 If a module containing built-in classes and functions has already been 52 annotated, such a module should be passed in as an additional argument: 53 54 annotator.process(module, builtins) 55 """ 56 57 from simplified import * 58 import simplify, fixnames # for the load function 59 import compiler 60 import os 61 62 class System: 63 64 """ 65 A class maintaining the state of the annotation system. When the system 66 counter can no longer be incremented by any annotation operation, the 67 system may be considered stable and fully annotated. 68 """ 69 70 def __init__(self): 71 self.count = 0 72 73 def init(self, node): 74 75 "Initialise a 'node' for annotation." 76 77 if not hasattr(node, "types"): 78 node.types = [] 79 80 def annotate(self, node, types): 81 82 "Annotate the given 'node' with the given 'types'." 83 84 self.init(node) 85 self.combine(node.types, types) 86 87 def combine(self, target, types): 88 89 """ 90 Combine the 'target' list with the given 'types', counting new members. 91 """ 92 93 for type in types: 94 if type not in target: 95 target.append(type) 96 self.count += 1 97 98 system = System() 99 100 # Exceptions. 101 102 class AnnotationError(SimplifiedError): 103 104 "An error in the annotation process." 105 106 pass 107 108 class AnnotationMessage(Exception): 109 110 "A lesser annotation error." 111 112 pass 113 114 # Annotation. 115 116 class Annotator(Visitor): 117 118 """ 119 The type annotator which traverses the program nodes, typically depth-first, 120 and maintains a record of the current set of types applying to the currently 121 considered operation. Such types are also recorded on the nodes, and a 122 special "system" record is maintained to monitor the level of annotation 123 activity with a view to recognising when no more annotations are possible. 124 125 Throughout the annotation activity, type information consists of lists of 126 Attribute objects where such objects retain information about the context of 127 the type (since a value in the program may be associated with an object or 128 class) and the actual type of the value being manipulated. Upon accessing 129 attribute information on namespaces, additional accessor information is also 130 exchanged - this provides a means of distinguishing between the different 131 types possible when the means of constructing the namespace may depend on 132 run-time behaviour. 133 134 Covered: Assign, CheckType, Conditional, Global, Import, InvokeRef, 135 InvokeFunction, LoadAttr, LoadExc, LoadName, LoadRef, LoadTemp, 136 Module, Not, Pass, Raise, ReleaseTemp, ReturnFromBlock, 137 ReturnFromFunction, StoreAttr, StoreName, StoreTemp, Subprogram, 138 Try. 139 """ 140 141 def __init__(self, importer=None): 142 143 "Initialise the visitor with an optional 'importer'." 144 145 Visitor.__init__(self) 146 self.system = system 147 self.importer = importer or Importer() 148 149 # Satisfy visitor issues. 150 151 self.visitor = self 152 153 def process(self, module, builtins=None): 154 155 """ 156 Process the given 'module', using the optional 'builtins' to access 157 built-in classes and functions. 158 """ 159 160 self.subprograms = [] 161 self.current_subprograms = [] 162 self.current_namespaces = [] 163 self.rerun_subprograms = {} 164 self.namespace = None 165 self.module = module 166 167 # Give constants their own namespace. 168 169 for value, constant in module.simplifier.constants.items(): 170 constant.namespace = Namespace() 171 172 # Process the module, supplying builtins if possible. 173 174 self.builtins = builtins 175 self.global_namespace = Namespace() 176 177 if builtins is not None: 178 self.builtins_namespace = builtins.namespace 179 else: 180 self.builtins_namespace = self.global_namespace 181 182 # NOTE: Not declaring module namespace usage, even though it is used. 183 184 return self.process_node(module, self.global_namespace, 0) 185 186 def process_node(self, node, locals, using_module_namespace): 187 188 """ 189 Process a subprogram or module 'node', indicating the initial 'locals'. 190 Return an annotated subprogram or module. Note that this method may 191 mutate nodes in the original program. 192 """ 193 194 # Recursion test. 195 196 if node in self.current_subprograms: 197 if not self.rerun_subprograms.has_key(node): 198 self.rerun_subprograms[node] = [] 199 self.rerun_subprograms[node].append(locals) 200 return node 201 202 # Record the current subprogram and namespace. 203 204 self.current_subprograms.append(node) 205 206 # Determine the namespace. 207 208 self.current_namespaces.append(self.namespace) 209 self.namespace = locals 210 211 # Add namespace details to any structure involved. 212 213 if getattr(node, "structure", None) is not None: 214 node.structure.namespace = Namespace() 215 216 # Initialise bases where appropriate. 217 218 if hasattr(node.structure, "bases"): 219 base_refs = [] 220 for base in node.structure.bases: 221 self.dispatch(base) 222 base_refs.append(self.namespace.types) 223 node.structure.base_refs = base_refs 224 225 # Dispatch to the code itself. 226 227 node.namespace = self.namespace 228 self.set_module_namespace(using_module_namespace) 229 230 result = self.dispatch(node) 231 self.extract_results(result) 232 233 while self.rerun_subprograms.has_key(node): 234 all_rerun_locals = self.rerun_subprograms[node] 235 del self.rerun_subprograms[node] 236 for rerun_locals in all_rerun_locals: 237 #print "Re-running", node, "with", rerun_locals 238 239 self.namespace = rerun_locals 240 node.namespace = rerun_locals 241 self.set_module_namespace(using_module_namespace) 242 243 result = self.dispatch(node) 244 self.extract_results(result) 245 246 # Restore the previous subprogram and namespace. 247 248 self.namespace = self.current_namespaces.pop() 249 self.current_subprograms.pop() 250 self.reset_module_namespace(using_module_namespace) 251 252 return result 253 254 def set_module_namespace(self, using_module_namespace): 255 256 """ 257 In order to keep global accesses working, the module namespace must be 258 adjusted. 259 """ 260 261 if using_module_namespace: 262 self.module.namespace = self.namespace 263 264 def reset_module_namespace(self, using_module_namespace): 265 266 """ 267 In order to keep global accesses working, the module namespace must be 268 reset. 269 """ 270 271 if using_module_namespace: 272 self.module.namespace = self.namespace 273 274 def extract_results(self, result): 275 276 "Extract results from the namespace." 277 278 result.namespace = self.namespace 279 if hasattr(result, "raises"): 280 combine(result.raises, self.namespace.raises) 281 if hasattr(result, "returns"): 282 combine(result.returns, self.namespace.returns) 283 if hasattr(result, "return_locals"): 284 combine(result.return_locals, self.namespace.return_locals) 285 286 def annotate(self, node, types=None): 287 288 """ 289 Annotate the given 'node' in the system, using either the optional 290 'types' or the namespace's current type information. 291 """ 292 293 if types is None: 294 self.system.annotate(node, self.namespace.types) 295 else: 296 self.system.annotate(node, types) 297 298 def annotate_parameters(self, node, items): 299 300 """ 301 Annotate the given 'node' using the given 'items' and updating the 302 system's annotation counter. 303 """ 304 305 if not hasattr(node, "paramtypes"): 306 node.paramtypes = {} 307 308 for param, types in items: 309 if not node.paramtypes.has_key(param): 310 node.paramtypes[param] = [] 311 self.system.combine(node.paramtypes[param], types) 312 313 # Visitor methods. 314 315 def default(self, node): 316 317 """ 318 Process the given 'node', given that it does not have a specific 319 handler. 320 """ 321 322 raise AnnotationMessage, "Node '%s' not supported." % node 323 324 def dispatch(self, node, *args): 325 try: 326 return Visitor.dispatch(self, node, *args) 327 except AnnotationError, exc: 328 exc.add(node) 329 raise 330 except AnnotationMessage, exc: 331 raise AnnotationError(exc, node) 332 333 # Specific node methods. 334 335 def visitAssign(self, assign): 336 337 """ 338 Return the 'assign' node whose contents (merely a group of nodes) have 339 been processed. 340 """ 341 342 assign.code = self.dispatches(assign.code) 343 return assign 344 345 def visitCheckType(self, checktype): 346 347 """ 348 Return the 'checktype' node, processing the expression to find the 349 possible types of the exception, and processing each choice to build a 350 list of checked types for the exception. 351 """ 352 353 inverted = getattr(checktype, "inverted", 0) 354 checktype.expr = self.dispatch(checktype.expr) 355 356 expr_types = self.namespace.types 357 choice_types = [] 358 choices = [] 359 360 for choice in checktype.choices: 361 choices.append(self.dispatch(choice)) 362 choice_types += self.namespace.types 363 364 for expr_type in expr_types: 365 in_choices = expr_type.type.get_class() in choice_types 366 367 # Filter out types not in the choices list unless the operation is 368 # inverted; in which case, filter out types in the choices list. 369 370 if not inverted and not in_choices or inverted and in_choices: 371 self._prune_non_accesses(checktype.expr, expr_type) 372 373 return checktype 374 375 def visitConditional(self, conditional): 376 377 """ 378 Return the 'conditional' node, processing the test, body and else 379 clauses and recording their processed forms. The body and else clauses 380 are processed within their own namespaces, and the test is also 381 processed in its own namespace if 'isolate_test' is set on the 382 'conditional' node. 383 """ 384 385 # Conditionals keep local namespace changes isolated. 386 # With Return nodes inside the body/else sections, the changes are 387 # communicated to the caller. 388 389 is_module = self.namespace is self.module.namespace 390 391 # Where the test is closely associated with the body, save the namespace 392 # before entering the test. 393 394 if conditional.isolate_test: 395 saved_namespace = self.namespace 396 self.namespace = Namespace() 397 if is_module: 398 self.module.namespace = self.namespace 399 self.namespace.merge_namespace(saved_namespace) 400 401 conditional.test = self.dispatch(conditional.test) 402 403 # Where the test may affect the body and the else clause, save the 404 # namespace after processing the test. 405 406 if not conditional.isolate_test: 407 saved_namespace = self.namespace 408 self.namespace = Namespace() 409 if is_module: 410 self.module.namespace = self.namespace 411 self.namespace.merge_namespace(saved_namespace) 412 413 # NOTE: Exception recording. 414 415 else: 416 test_raises = [] 417 combine(test_raises, self.namespace.raises) 418 419 # Process the body clause. 420 421 conditional.body = self.dispatches(conditional.body) 422 body_namespace = self.namespace 423 424 # Use the saved namespace as a template for the else clause. 425 426 self.namespace = Namespace() 427 if is_module: 428 self.module.namespace = self.namespace 429 self.namespace.merge_namespace(saved_namespace) 430 431 # Process the else clause. 432 433 conditional.else_ = self.dispatches(conditional.else_) 434 else_namespace = self.namespace 435 436 # Merge the body and else namespaces. 437 438 self.namespace = Namespace() 439 if is_module: 440 self.module.namespace = self.namespace 441 self.namespace.merge_namespace(body_namespace) 442 self.namespace.merge_namespace(else_namespace) 443 444 # NOTE: Test of exception type pruning based on the test/body. 445 # Note that the checked exceptions are tested for re-raising. 446 447 if conditional.isolate_test: 448 for exc_type in test_raises: 449 if exc_type not in body_namespace.raises: 450 self.namespace.revoke_exception_type(exc_type) 451 452 return conditional 453 454 def visitGlobal(self, global_): 455 456 """ 457 Return the 'global_' node unprocessed since namespaces should have 458 already been altered to take global names into consideration. 459 """ 460 461 return global_ 462 463 def visitImport(self, import_): 464 465 """ 466 Return the 'import_' node, importing the module with the stated name 467 and storing details on the node. 468 """ 469 470 module = self.importer.load(import_.name, self.builtins, getattr(import_, "alias", None)) 471 if module is not None: 472 self.namespace.set_types([module]) 473 else: 474 self.namespace.set_types([]) 475 self.annotate(import_) # mainly for viewing purposes 476 return import_ 477 478 def _visitInvoke(self, invoke, invocation_types, have_args): 479 480 """ 481 Return the processed 'invoke' node, using the given 'invocation_types' 482 as the list of callables to be investigated for instantiation or for the 483 invocation of functions or blocks. If 'have_args' is a true value, any 484 invocation or instantiation will involve arguments. 485 """ 486 487 # Now locate and invoke the subprogram. This can be complicated because 488 # the target may be a class or object, and there may be many different 489 # related subprograms. 490 491 invocations = [] 492 493 # Visit each callable in turn, finding subprograms. 494 495 for attr in invocation_types: 496 497 # Deal with class invocations by providing instance objects. 498 # Here, each class is queried for the __init__ method, which may 499 # exist for some combinations of classes in a hierarchy but not for 500 # others. 501 502 if isinstance(attr.type, Class): 503 attributes = get_attributes(attr.type, "__init__") 504 505 # Deal with object invocations by using __call__ methods. 506 507 elif isinstance(attr.type, Instance): 508 attributes = get_attributes(attr.type, "__call__") 509 510 # Normal functions or methods are more straightforward. 511 # Here, we model them using an attribute with no context and with 512 # no associated accessor. 513 514 else: 515 attributes = [(attr, None)] 516 517 # Inspect each attribute and extract the subprogram. 518 519 for attribute, accessor in attributes: 520 521 # If a class is involved, presume that it must create a new 522 # object. 523 524 if isinstance(attr.type, Class): 525 526 # Instantiate the class. 527 528 instance = self.new_instance(invoke, attr.type) 529 530 # For instantiations, switch the context. 531 532 if attribute is not None: 533 attribute = Attribute(instance, attribute.type) 534 535 # Request an instance-specific initialiser. 536 537 attribute = attr.type.get_attribute_for_instance(attribute, instance) 538 539 # Skip cases where no callable is found. 540 541 if attribute is not None: 542 543 # If a subprogram is defined, invoke it. 544 545 self.invoke_subprogram(invoke, attribute) 546 if attribute.type not in invocations: 547 invocations.append(attribute.type) 548 549 elif not isinstance(attr.type, Class): 550 print "Invocation type is None for", accessor 551 552 else: 553 554 # Test to see if no arguments were supplied in cases where no 555 # initialiser was found. 556 557 if have_args: 558 raise AnnotationMessage, "No initialiser found for '%s' with arguments." % attr.type 559 560 # Special case: initialisation. 561 562 if isinstance(attr.type, Class): 563 564 # Associate the instance with the result of this invocation. 565 566 self.namespace.set_types([Attribute(None, instance)]) 567 self.annotate(invoke) 568 569 # Remember the invocations that were found, along with the return type 570 # information. 571 572 invoke.invocations = invocations 573 self.namespace.set_types(getattr(invoke, "types", [])) 574 return invoke 575 576 def visitInvokeRef(self, invoke): 577 578 """ 579 Return the processed 'invoke' node, first finding the callables 580 indicated by the reference. 581 """ 582 583 # Where the invocation belongs to an instance but the invoked subprogram 584 # does not, request a special copy. 585 586 instance = getattr(invoke, "instance", None) 587 if instance is not None and getattr(invoke.ref, "instance", None) is None: 588 if invoke.ref.copies.has_key(instance): 589 invoke.ref = invoke.ref.copies[instance] 590 else: 591 invoke.ref = invoke.ref.copy(instance) 592 #print "Created", invoke.ref, "for", getattr(invoke.ref, "instance", None) 593 invoke.ref.module.simplifier.subnames[invoke.ref.full_name()] = invoke.ref 594 invocation_types = [Attribute(None, invoke.ref)] 595 return self._visitInvoke(invoke, invocation_types, have_args=0) 596 597 def visitInvokeFunction(self, invoke): 598 599 """ 600 Return the processed 'invoke' node, first finding the callables 601 indicated by the expression. 602 """ 603 604 invoke.expr = self.dispatch(invoke.expr) 605 invocation_types = self.namespace.types 606 607 # Invocation processing starts with making sure that the arguments have 608 # been processed. 609 610 return self._visitInvoke(invoke, invocation_types, have_args=self.process_args(invoke)) 611 612 def visitLoadAttr(self, loadattr): 613 614 """ 615 Return the 'loadattr' node, processing and storing the expression, and 616 using the expression's types to construct records of accesses and 617 non-accesses using the stated attribute name. 618 """ 619 620 loadattr.expr = self.dispatch(loadattr.expr) 621 types = [] 622 non_accesses = [] 623 accesses = {} 624 for attr in self.namespace.types: 625 attributes = get_attributes(attr.type, loadattr.name) 626 if not attributes: 627 if not attr in non_accesses: 628 non_accesses.append(attr) 629 combine(self.namespace.raises, self.get_builtin_instances(loadattr, "AttributeError")) 630 631 # Revoke this type from any name involved. 632 633 self._prune_non_accesses(loadattr.expr, attr) 634 635 for attribute, accessor in attributes: 636 if attribute is not None: 637 types.append(attribute) 638 if not accesses.has_key(attr.type): 639 accesses[attr.type] = [] 640 if not (attribute, accessor) in accesses[attr.type]: 641 accesses[attr.type].append((attribute, accessor)) 642 else: 643 if not attr in non_accesses: 644 non_accesses.append(attr) 645 combine(self.namespace.raises, self.get_builtin_instances(loadattr, "AttributeError")) 646 647 # Revoke this type from any name involved. 648 649 self._prune_non_accesses(loadattr.expr, attr) 650 651 if not types: 652 print "No attribute found for", loadattr.name, "given", self.namespace.types 653 self.namespace.set_types(types) 654 loadattr.non_accesses = non_accesses 655 loadattr.accesses = accesses 656 self.annotate(loadattr) 657 return loadattr 658 659 def _prune_non_accesses(self, expr, attr): 660 661 """ 662 Prune type information from 'expr' where the given 'attr' has been 663 shown to be a non-access. 664 """ 665 666 if isinstance(expr, LoadName): 667 self.namespace.revoke(expr.name, attr) 668 elif isinstance(expr, LoadExc): 669 self.namespace.revoke_exception_type(attr) 670 elif isinstance(expr, LoadTemp): 671 self.namespace.revoke_temp_type(getattr(expr, "index", None), attr) 672 673 # LoadAttr cannot be pruned since this might unintentionally prune 674 # legitimate types from other applications of the referenced type, it 675 # almost certainly doesn't take "concurrent" mutation into 676 # consideration (where in a running program, the pruned type is actually 677 # reintroduced, making the pruning invalid), and there is no easy way of 678 # preserving the meaning of a namespace without either creating lots of 679 # specialised instances, and even then... 680 681 #elif isinstance(expr, LoadAttr): 682 # for expr_attr in expr.expr.types: 683 # if hasattr(expr_attr.type, "namespace"): 684 # expr_attr.type.namespace.revoke(expr.name, attr) 685 686 def visitLoadExc(self, loadexc): 687 688 """ 689 Return the 'loadexc' node, discovering the possible exception types 690 raised. 691 """ 692 693 self.namespace.set_types(self.namespace.raises) 694 self.annotate(loadexc) 695 return loadexc 696 697 def visitLoadName(self, loadname): 698 699 """ 700 Return the 'loadname' node, processing the name information on the node 701 to determine which types are involved with the name. 702 """ 703 704 self.namespace.set_types(self.namespace.load(loadname.name)) 705 result = loadname 706 self.annotate(result) 707 return result 708 709 def visitLoadRef(self, loadref): 710 711 """ 712 Return the 'loadref' node, obtaining type information about the 713 reference stated on the node. 714 """ 715 716 self.namespace.set_types([Attribute(None, loadref.ref)]) 717 self.annotate(loadref) 718 return loadref 719 720 def visitLoadTemp(self, loadtemp): 721 722 """ 723 Return the 'loadtemp' node, obtaining type information about the 724 temporary variable accessed, and removing variable information where the 725 'release' attribute has been set on the node. 726 """ 727 728 index = getattr(loadtemp, "index", None) 729 try: 730 if getattr(loadtemp, "release", 0): 731 self.namespace.set_types(self.namespace.temp[index].pop()) 732 else: 733 self.namespace.set_types(self.namespace.temp[index][-1]) 734 except KeyError: 735 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 736 self.annotate(loadtemp) 737 return loadtemp 738 739 def visitModule(self, module): 740 741 """ 742 Return the processed 'module' whose contents (merely a group of nodes) 743 are processed. 744 """ 745 746 module.code = self.dispatches(module.code) 747 return module 748 749 def visitNot(self, not_): 750 751 "Return the 'not_' node whose expression is processed." 752 753 not_.expr = self.dispatch(not_.expr) 754 return not_ 755 756 def visitPass(self, pass_): 757 758 "Return the unprocessed 'pass_' node." 759 760 return pass_ 761 762 def visitRaise(self, raise_): 763 764 """ 765 Return the 'raise_' node, processing any traceback information along 766 with the raised exception expression, converting the node into a kind of 767 invocation where the expression is found not to be an invocation itself. 768 This node affects the namespace, adding exception types to the list of 769 those raised in the namespace. 770 """ 771 772 if getattr(raise_, "traceback", None) is not None: 773 raise_.traceback = self.dispatch(raise_.traceback) 774 raise_.expr = self.dispatch(raise_.expr) 775 776 # Handle bare name exceptions by converting any classes to instances. 777 778 if not isinstance(raise_.expr, InvokeFunction): 779 raise_.pos_args = [] 780 raise_.kw_args = {} 781 raise_.star = None 782 raise_.dstar = None 783 types = [] 784 for attr in self.namespace.types: 785 if isinstance(attr.type, Class): 786 self._visitInvoke(raise_, [attr], have_args=0) 787 types += self.namespace.types 788 else: 789 types = self.namespace.types 790 791 combine(self.namespace.raises, types) 792 return raise_ 793 794 def visitReleaseTemp(self, releasetemp): 795 796 """ 797 Return the 'releasetemp' node, removing temporary variable information 798 from the current namespace. 799 """ 800 801 index = getattr(releasetemp, "index", None) 802 try: 803 self.namespace.temp[index].pop() 804 except KeyError: 805 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 806 except IndexError: 807 pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index 808 return releasetemp 809 810 def visitResetExc(self, resetexc): 811 self.namespace.raises = [] 812 return resetexc 813 814 def visitReturn(self, return_): 815 816 """ 817 Return the 'return_' node, processing any expression and obtaining type 818 information to be accumulated in the current namespace's list of return 819 types. A snapshot of the namespace is taken for the purposes of 820 reconciling or merging namespaces where subprograms actually share 821 locals with their callers. 822 """ 823 824 if hasattr(return_, "expr"): 825 return_.expr = self.dispatch(return_.expr) 826 combine(self.namespace.returns, self.namespace.types) 827 self.annotate(return_) 828 self.namespace.snapshot() 829 return return_ 830 831 visitReturnFromBlock = visitReturn 832 visitReturnFromFunction = visitReturn 833 834 def visitStoreAttr(self, storeattr): 835 836 """ 837 Return the 'storeattr' node, processing the expression and target, and 838 using the type information obtained to build records of legitimate 839 writes to the stated attribute, along with "impossible" non-writes to 840 the attribute. 841 """ 842 843 storeattr.expr = self.dispatch(storeattr.expr) 844 expr = self.namespace.types 845 storeattr.lvalue = self.dispatch(storeattr.lvalue) 846 writes = {} 847 non_writes = [] 848 for attr in self.namespace.types: 849 # NOTE: Impose "atomic" constraints on certain types. 850 if attr is None: 851 if not attr in non_writes: 852 non_writes.append(attr) 853 continue 854 attr.type.namespace.add(storeattr.name, expr) 855 writes[attr.type] = attr.type.namespace.load(storeattr.name) 856 if not writes: 857 print "Unable to store attribute", storeattr.name, "given", self.namespace.types 858 storeattr.writes = writes 859 storeattr.non_writes = non_writes 860 return storeattr 861 862 def visitStoreName(self, storename): 863 864 """ 865 Return the 'storename' node, processing the expression on the node and 866 associating the type information obtained with the stated name in the 867 current namespace. 868 """ 869 870 storename.expr = self.dispatch(storename.expr) 871 self.namespace.store(storename.name, self.namespace.types) 872 self.annotate(storename) 873 return storename 874 875 def visitStoreTemp(self, storetemp): 876 877 """ 878 Return the 'storetemp' node, processing the expression on the node and 879 associating the type information obtained with a temporary variable in 880 the current namespace. 881 """ 882 883 storetemp.expr = self.dispatch(storetemp.expr) 884 index = getattr(storetemp, "index", None) 885 if not self.namespace.temp.has_key(index): 886 self.namespace.temp[index] = [] 887 self.namespace.temp[index].append(self.namespace.types) 888 return storetemp 889 890 def visitSubprogram(self, subprogram): 891 892 """ 893 Return the 'subprogram' node, processing its contents (a group of nodes 894 comprising the subprogram). 895 """ 896 897 subprogram.code = self.dispatches(subprogram.code) 898 return subprogram 899 900 def visitTry(self, try_): 901 902 """ 903 Return the 'try_' node, processing the body clause in its own namespace 904 derived from the current namespace, processing any handler clause using 905 the namespace information accumulated in the body, and processing any 906 else and finally clauses, attempting to supply each with appropriate 907 namespace information. 908 """ 909 910 is_module = self.namespace is self.module.namespace 911 912 try_.body = self.dispatches(try_.body) 913 914 # Save the namespace from the body. 915 916 body_namespace = Namespace() 917 body_namespace.merge_namespace(self.namespace) 918 919 # Process the handler. 920 921 if hasattr(try_, "handler"): 922 try_.handler = self.dispatches(try_.handler) 923 924 # Save the namespace from the handler. 925 926 handler_namespace = Namespace() 927 handler_namespace.merge_namespace(self.namespace) 928 929 # Remember the raised exceptions encountered so far. 930 931 raises = self.namespace.raises 932 933 # Process the else clause. 934 935 if hasattr(try_, "else_"): 936 937 # Restore the body namespace for the else clause. 938 939 self.namespace = body_namespace 940 if is_module: 941 self.module.namespace = self.namespace 942 943 # Empty the raised exceptions for the else clause. 944 945 self.namespace.raises = [] 946 try_.else_ = self.dispatches(try_.else_) 947 self.namespace.raises = raises 948 949 # Merge the namespaces. 950 951 self.namespace = Namespace() 952 if is_module: 953 self.module.namespace = self.namespace 954 self.namespace.merge_namespace(body_namespace) 955 self.namespace.merge_namespace(handler_namespace) 956 957 # Process the finally clause, if any. 958 959 try_.finally_ = self.dispatches(try_.finally_) 960 return try_ 961 962 def visitYield(self, yield_): 963 raise NotImplementedError, "The yield statement is not currently supported." 964 965 # Utility methods. 966 967 def get_builtin_instances(self, node, name): 968 return [Attribute(None, self.new_instance(node, attr.type)) for attr in self.builtins.namespace[name]] 969 970 def new_instance(self, node, type): 971 972 "For the given 'node', obtain an instance from the given 'type'." 973 974 if not type.has_instance(node): 975 instance = Instance() 976 instance.namespace = Namespace() 977 instance.namespace.store("__class__", [Attribute(None, type)]) 978 type.add_instance(node, instance) 979 else: 980 instance = type.get_instance(node) 981 982 return instance 983 984 def invoke_subprogram(self, invoke, attribute): 985 986 """ 987 Invoke using the given 'invoke' node the subprogram represented by the 988 given 'attribute'. 989 """ 990 991 # Test for context information, making it into a real attribute. 992 993 if attribute.context is not None: 994 context = Attribute(None, attribute.context) 995 target = attribute.type 996 else: 997 context = None 998 target = attribute.type 999 1000 # Test to see if anything has changed. 1001 1002 if hasattr(invoke, "syscount") and invoke.syscount.has_key(target) and invoke.syscount[target] == self.system.count: 1003 return 1004 1005 # Remember the state of the system. 1006 1007 else: 1008 if not hasattr(invoke, "syscount"): 1009 invoke.syscount = {} 1010 invoke.syscount[target] = self.system.count 1011 1012 # Provide the correct namespace for the invocation. 1013 # This may be a "shared" namespace... 1014 1015 if getattr(invoke, "share_locals", 0): 1016 namespace = Namespace() 1017 namespace.merge_namespace(self.namespace, everything=0) 1018 using_module_namespace = self.namespace is self.module.namespace 1019 1020 # Or it may be a structure... 1021 1022 elif getattr(target, "structure", None): 1023 namespace = Namespace() 1024 using_module_namespace = 0 1025 1026 # Or it may be a new namespace populated with the supplied parameters. 1027 1028 else: 1029 items = self.make_items(invoke, target, context) 1030 namespace = Namespace() 1031 namespace.merge_items(items) 1032 using_module_namespace = 0 1033 1034 # NOTE: Avoid PEP 227 (nested scopes) whilst permitting references to a 1035 # NOTE: subprogram within itself. Do not define the name of the function 1036 # NOTE: within a method definition. 1037 1038 if getattr(target, "name", None) is not None and not getattr(target, "is_method", 0): 1039 namespace.store(target.name, [Attribute(None, target)]) 1040 1041 # Process the subprogram. 1042 1043 self.process_node(target, namespace, using_module_namespace) 1044 1045 # NOTE: Improve and verify this. 1046 # If the invocation returns a value, acquire the return types. 1047 1048 if getattr(target, "returns_value", 0): 1049 self.namespace.set_types(target.returns) 1050 self.annotate(invoke) 1051 1052 # If it is a normal block, merge the locals. 1053 # This can happen in addition to the above because for things like 1054 # logical expressions, the namespace can be modified whilst values are 1055 # returned as results. 1056 1057 if getattr(invoke, "share_locals", 0): 1058 self.namespace.reset() 1059 1060 # Merge the locals snapshots. 1061 1062 for locals in target.return_locals: 1063 1064 # For blocks returning values (such as operations), do not merge 1065 # snapshots or results. 1066 1067 if getattr(target, "returns_value", 0): 1068 self.namespace.merge_namespace(locals, everything=0) 1069 1070 # For blocks not returning values (such as loops), merge 1071 # snapshots and results since they contain details of genuine 1072 # returns. 1073 1074 else: 1075 self.namespace.merge_namespace(locals) 1076 1077 # Incorporate any raised exceptions. 1078 1079 if not hasattr(invoke, "raises"): 1080 invoke.raises = [] 1081 combine(invoke.raises, target.raises) 1082 combine(self.namespace.raises, target.raises) 1083 1084 def process_args(self, invocation): 1085 1086 """ 1087 Process the arguments associated with an 'invocation'. Return whether 1088 any arguments were processed. 1089 """ 1090 1091 invocation.pos_args = self.dispatches(invocation.pos_args) 1092 invocation.kw_args = self.dispatch_dict(invocation.kw_args) 1093 1094 # Get type information for star and dstar arguments. 1095 1096 if invocation.star is not None: 1097 param, default = invocation.star 1098 default = self.dispatch(default) 1099 invocation.star = param, default 1100 1101 if invocation.dstar is not None: 1102 param, default = invocation.dstar 1103 default = self.dispatch(default) 1104 invocation.dstar = param, default 1105 1106 if invocation.pos_args or invocation.kw_args or invocation.star or invocation.dstar: 1107 return 1 1108 else: 1109 return 0 1110 1111 def make_items(self, invocation, subprogram, context): 1112 1113 """ 1114 Make an items mapping for the 'invocation' of the 'subprogram' using the 1115 given 'context' (which may be None). 1116 """ 1117 1118 if context is not None: 1119 pos_args = [Self(context)] + invocation.pos_args 1120 else: 1121 pos_args = invocation.pos_args 1122 1123 # Duplicate the keyword arguments - we remove them in processing below. 1124 1125 kw_args = {} 1126 kw_args.update(invocation.kw_args) 1127 1128 # Sort the arguments into positional and keyword arguments. 1129 1130 params = subprogram.params 1131 items = [] 1132 star_args = [] 1133 1134 # Match each positional argument, taking excess arguments as star args. 1135 1136 for arg in pos_args: 1137 if params: 1138 param, default = params[0] 1139 if arg is None: 1140 arg = default 1141 if hasattr(arg, "types"): 1142 items.append((param, arg.types)) 1143 else: 1144 items.append((param, [])) # Annotation has not succeeded. 1145 params = params[1:] 1146 else: 1147 star_args.append(arg) 1148 1149 # Collect the remaining defaults. 1150 1151 while params: 1152 param, default = params[0] 1153 if kw_args.has_key(param): 1154 arg = kw_args[param] 1155 del kw_args[param] 1156 elif default is not None: 1157 arg = self.dispatch(default) 1158 else: 1159 raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param) 1160 if hasattr(arg, "types"): 1161 items.append((param, arg.types)) 1162 else: 1163 items.append((param, [])) # Annotation has not succeeded. 1164 params = params[1:] 1165 1166 dstar_args = kw_args.items() 1167 1168 # Construct temporary objects. 1169 1170 if star_args: 1171 star_invocation = self.make_star_args(invocation, subprogram, star_args) 1172 self.dispatch(star_invocation) 1173 star_types = star_invocation.types 1174 else: 1175 star_types = None 1176 1177 if dstar_args: 1178 dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args) 1179 self.dispatch(dstar_invocation) 1180 dstar_types = dstar_invocation.types 1181 else: 1182 dstar_types = None 1183 1184 # NOTE: Merge the objects properly. 1185 1186 star_types = star_types or invocation.star and invocation.star.types 1187 dstar_types = dstar_types or invocation.dstar and invocation.dstar.types 1188 1189 # Add star and dstar. 1190 1191 if star_types is not None: 1192 if subprogram.star is not None: 1193 param, default = subprogram.star 1194 items.append((param, star_types)) 1195 else: 1196 raise AnnotationMessage, "Invocation provides unwanted *args." 1197 elif subprogram.star is not None: 1198 param, default = subprogram.star 1199 if not hasattr(default, "types"): 1200 subprogram.star = param, self.dispatch(default) # NOTE: Review reprocessing. 1201 items.append((param, default.types)) 1202 1203 if dstar_types is not None: 1204 if subprogram.dstar is not None: 1205 param, default = subprogram.dstar 1206 items.append((param, dstar_types)) 1207 else: 1208 raise AnnotationMessage, "Invocation provides unwanted **args." 1209 elif subprogram.dstar is not None: 1210 param, default = subprogram.dstar 1211 if not hasattr(default, "types"): 1212 subprogram.dstar = param, self.dispatch(default) # NOTE: Review reprocessing. 1213 items.append((param, default.types)) 1214 1215 # Record the parameter types. 1216 1217 self.annotate_parameters(subprogram, items) 1218 return subprogram.paramtypes.items() 1219 1220 def make_star_args(self, invocation, subprogram, star_args): 1221 1222 "Make a subprogram which initialises a list containing 'star_args'." 1223 1224 if not hasattr(invocation, "stars"): 1225 invocation.stars = {} 1226 1227 if not invocation.stars.has_key(subprogram.full_name()): 1228 instance = getattr(invocation, "instance", None) 1229 1230 code=[ 1231 StoreTemp( 1232 instance=instance, 1233 expr=InvokeFunction( 1234 invocation.original, 1235 instance=instance, 1236 expr=LoadAttr( 1237 instance=instance, 1238 expr=LoadRef( 1239 instance=instance, 1240 ref=self.builtins 1241 ), 1242 name="list", 1243 nstype="module", 1244 ), 1245 args=[], 1246 star=None, 1247 dstar=None 1248 ) 1249 ) 1250 ] 1251 1252 for arg in star_args: 1253 code.append( 1254 InvokeFunction( 1255 invocation.original, 1256 instance=instance, 1257 expr=LoadAttr( 1258 instance=instance, 1259 expr=LoadTemp( 1260 instance=instance 1261 ), 1262 name="append" 1263 ), 1264 args=[arg], 1265 star=None, 1266 dstar=None 1267 ) 1268 ) 1269 1270 code += [ 1271 Return( 1272 instance=instance, 1273 expr=LoadTemp( 1274 instance=instance, 1275 release=1 1276 ) 1277 ) 1278 ] 1279 1280 new_subprogram = Subprogram( 1281 instance=instance, 1282 name=None, 1283 returns_value=1, 1284 params=[], 1285 star=None, 1286 dstar=None, 1287 code=code 1288 ) 1289 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 1290 1291 invocation.stars[subprogram.full_name()] = InvokeRef( 1292 invocation.original, 1293 instance=instance, 1294 produces_result=1, 1295 ref=new_subprogram 1296 ) 1297 1298 return invocation.stars[subprogram.full_name()] 1299 1300 def make_dstar_args(self, invocation, subprogram, dstar_args): 1301 1302 """ 1303 Make a subprogram which initialises a dictionary built from the given 1304 'dstar_args'. 1305 """ 1306 1307 if not hasattr(invocation, "dstars"): 1308 invocation.dstars = {} 1309 1310 if not invocation.dstars.has_key(subprogram.full_name()): 1311 instance = getattr(invocation, "instance", None) 1312 1313 code=[ 1314 StoreTemp( 1315 instance=instance, 1316 expr=InvokeFunction( 1317 invocation.original, 1318 instance=instance, 1319 expr=LoadAttr( 1320 instance=instance, 1321 expr=LoadRef( 1322 instance=instance, 1323 ref=self.builtins 1324 ), 1325 name="dict", 1326 nstype="module", 1327 ) 1328 ) 1329 ) 1330 ] 1331 1332 for arg, value in dstar_args: 1333 1334 # NOTE: Constant not added to table. 1335 1336 constant = Constant( 1337 instance=instance, 1338 name=repr(arg), value=arg, namespace=Namespace() 1339 ) 1340 #constant.namespace.store("__class__", self.get_builtin_instances(invocation, constant.typename)) 1341 code += [ 1342 StoreTemp( 1343 instance=instance, 1344 expr=LoadRef( 1345 instance=instance, 1346 ref=constant 1347 ), 1348 index="const" 1349 ), 1350 StoreAttr( 1351 instance=instance, 1352 lvalue=LoadTemp( 1353 instance=instance, 1354 index="const" 1355 ), 1356 name="__class__", 1357 expr=LoadAttr( 1358 instance=instance, 1359 expr=LoadRef( 1360 instance=instance, 1361 ref=self.builtins 1362 ), 1363 name=constant.typename, 1364 nstype="module", 1365 ) 1366 ), 1367 InvokeFunction( 1368 invocation.original, 1369 instance=instance, 1370 expr=LoadAttr( 1371 instance=instance, 1372 expr=LoadTemp( 1373 instance=instance 1374 ), 1375 name="__setitem__" 1376 ), 1377 args=[ 1378 LoadTemp( 1379 instance=instance, 1380 index="const", 1381 release=1 1382 ), 1383 value 1384 ] 1385 ) 1386 ] 1387 1388 code += [ 1389 Return( 1390 instance=instance, 1391 expr=LoadTemp( 1392 instance=instance, 1393 release=1 1394 ) 1395 ) 1396 ] 1397 1398 new_subprogram = Subprogram( 1399 instance=instance, 1400 name=None, 1401 returns_value=1, 1402 params=[], 1403 star=None, 1404 dstar=None, 1405 code=code 1406 ) 1407 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 1408 1409 invocation.dstars[subprogram.full_name()] = InvokeRef( 1410 invocation.original, 1411 instance=instance, 1412 produces_result=1, 1413 ref=new_subprogram 1414 ) 1415 1416 return invocation.dstars[subprogram.full_name()] 1417 1418 # Namespace-related abstractions. 1419 1420 class Namespace: 1421 1422 """ 1423 A local namespace which may either relate to a genuine set of function 1424 locals or the initialisation of a structure or module. 1425 """ 1426 1427 def __init__(self): 1428 1429 """ 1430 Initialise the namespace with a mapping of local names to possible 1431 types, a list of return values and of possible returned local 1432 namespaces. The namespace also tracks the "current" types and a mapping 1433 of temporary value names to types. 1434 """ 1435 1436 self.names = {} 1437 self.returns = [] 1438 self.return_locals = [] 1439 self.raises = [] 1440 self.temp = {} 1441 self.types = [] 1442 1443 def set_types(self, types): 1444 1445 "Set the current collection of 'types'." 1446 1447 self.types = types[:] 1448 1449 def add(self, name, types): 1450 1451 "Add to the entry with the given 'name' the specified 'types'." 1452 1453 if self.names.has_key(name): 1454 combine(self.names[name], types) 1455 else: 1456 self.store(name, types) 1457 1458 def store(self, name, types): 1459 1460 "Store in (or associate with) the given 'name' the specified 'types'." 1461 1462 self.names[name] = types[:] 1463 1464 __setitem__ = store 1465 1466 def load(self, name): 1467 1468 "Load the types associated with the given 'name'." 1469 1470 return self.names[name] 1471 1472 __getitem__ = load 1473 1474 def has_key(self, name): 1475 return self.names.has_key(name) 1476 1477 def revoke(self, name, type): 1478 1479 "Revoke from the entry for the given 'name' the specified 'type'." 1480 1481 new_types = self.names[name][:] 1482 new_types.remove(type) 1483 self.names[name] = new_types 1484 1485 def revoke_exception_type(self, type): 1486 1487 "Revoke the given 'type' from the collection of exception types." 1488 1489 self.raises.remove(type) 1490 1491 def revoke_temp_type(self, index, type): 1492 1493 "Revoke from the temporary variable 'index' the given 'type'." 1494 1495 new_types = self.temp[index][-1][:] 1496 new_types.remove(type) 1497 self.temp[index][-1] = new_types 1498 1499 def merge_namespace(self, namespace, everything=1): 1500 1501 """ 1502 Merge items from the given 'namespace' with this namespace. When the 1503 optional 'everything' parameter is set to a false value (unlike the 1504 default), return values and locals snapshots will not be copied to this 1505 namespace. 1506 """ 1507 1508 self.merge_items(namespace.names.items()) 1509 combine(self.raises, namespace.raises) 1510 if everything: 1511 combine(self.returns, namespace.returns) 1512 combine(self.return_locals, namespace.return_locals) 1513 for name, values in namespace.temp.items(): 1514 if values: 1515 if not self.temp.has_key(name) or not self.temp[name]: 1516 self.temp[name] = [[]] 1517 combine(self.temp[name][-1], values[-1]) 1518 1519 def merge_items(self, items): 1520 1521 "Merge the given 'items' with this namespace." 1522 1523 for name, types in items: 1524 self.merge(name, types) 1525 1526 def merge(self, name, types): 1527 1528 "Merge the entry for the given 'name' and 'types' with this namespace." 1529 1530 if not self.names.has_key(name): 1531 self.names[name] = types[:] 1532 else: 1533 existing = self.names[name] 1534 combine(existing, types) 1535 1536 def snapshot(self): 1537 1538 "Make a snapshot of the locals and remember them." 1539 1540 namespace = Namespace() 1541 namespace.merge_namespace(self) 1542 self.return_locals.append(namespace) 1543 1544 def reset(self): 1545 1546 "Reset a namespace in preparation for merging with returned locals." 1547 1548 self.names = {} 1549 1550 def __repr__(self): 1551 return repr(self.names) + " (temp) " + repr(self.temp) 1552 1553 class Importer: 1554 1555 "An import machine, searching for and loading modules." 1556 1557 def __init__(self, path=None): 1558 1559 """ 1560 Initialise the importer with the given search 'path' - a list of 1561 directories to search for Python modules. 1562 """ 1563 1564 self.path = path or [os.getcwd()] 1565 self.path.append(libdir) 1566 self.modules = {} 1567 1568 def find_in_path(self, name): 1569 1570 """ 1571 Find the given module 'name' in the search path, returning None where no 1572 such module could be found, or a 2-tuple from the 'find' method 1573 otherwise. 1574 """ 1575 1576 for d in self.path: 1577 m = self.find(d, name) 1578 if m: return m 1579 return None 1580 1581 def find(self, d, name): 1582 1583 """ 1584 In the directory 'd', find the given module 'name', where 'name' can 1585 either refer to a single file module or to a package. Return None if the 1586 'name' cannot be associated with either a file or a package directory, 1587 or a 2-tuple from '_find_package' or '_find_module' otherwise. 1588 """ 1589 1590 m = self._find_package(d, name) 1591 if m: return m 1592 m = self._find_module(d, name) 1593 if m: return m 1594 return None 1595 1596 def _find_module(self, d, name): 1597 1598 """ 1599 In the directory 'd', find the given module 'name', returning None where 1600 no suitable file exists in the directory, or a 2-tuple consisting of 1601 None (indicating that no package directory is involved) and a filename 1602 indicating the location of the module. 1603 """ 1604 1605 name_py = name + os.extsep + "py" 1606 filename = self._find_file(d, name_py) 1607 if filename: 1608 return None, filename 1609 return None 1610 1611 def _find_package(self, d, name): 1612 1613 """ 1614 In the directory 'd', find the given package 'name', returning None 1615 where no suitable package directory exists, or a 2-tuple consisting of 1616 a directory (indicating the location of the package directory itself) 1617 and a filename indicating the location of the __init__.py module which 1618 declares the package's top-level contents. 1619 """ 1620 1621 filename = self._find_file(d, name) 1622 if filename: 1623 init_py = "__init__" + os.path.extsep + "py" 1624 init_py_filename = self._find_file(filename, init_py) 1625 if init_py_filename: 1626 return filename, init_py_filename 1627 return None 1628 1629 def _find_file(self, d, filename): 1630 1631 """ 1632 Return the filename obtained when searching the directory 'd' for the 1633 given 'filename', or None if no actual file exists for the filename. 1634 """ 1635 1636 filename = os.path.join(d, filename) 1637 if os.path.exists(filename): 1638 return filename 1639 else: 1640 return None 1641 1642 def load(self, name, builtins, alias=None): 1643 1644 """ 1645 Load the module or package with the given 'name' and using the specified 1646 'builtins'. Return an Attribute object referencing the loaded module or 1647 package, or None if no such module or package exists. 1648 """ 1649 1650 if self.modules.has_key(name): 1651 return Attribute(None, self.modules[name]) 1652 1653 path = name.split(".") 1654 m = self.find_in_path(path[0]) 1655 if not m: 1656 return None # NOTE: Import error. 1657 d, filename = m 1658 1659 if self.modules.has_key(path[0]): 1660 top = module = self.modules[path[0]] 1661 else: 1662 top = module = self.modules[path[0]] = load(filename, builtins, path[0], self, no_annotate=1) 1663 annotate(module, builtins, self) 1664 1665 if len(path) > 1: 1666 path_so_far = path[:1] 1667 for p in path[1:]: 1668 path_so_far.append(p) 1669 m = self.find(d, p) 1670 if not m: 1671 return None # NOTE: Import error. 1672 d, filename = m 1673 module_name = ".".join(path_so_far) 1674 1675 if self.modules.has_key(module_name): 1676 submodule = self.modules[module_name] 1677 else: 1678 submodule = self.modules[module_name] = load(filename, builtins, module_name, self, no_annotate=1) 1679 annotate(submodule, builtins, self) 1680 1681 # Store the submodule within its parent module. 1682 1683 module.namespace[p] = [Attribute(None, submodule)] 1684 module = submodule 1685 1686 if alias: 1687 return Attribute(None, module) 1688 else: 1689 return Attribute(None, top) 1690 1691 def combine(target, additions): 1692 1693 """ 1694 Merge into the 'target' sequence the given 'additions', preventing duplicate 1695 items. 1696 """ 1697 1698 for addition in additions: 1699 if addition not in target: 1700 target.append(addition) 1701 1702 def find_attributes(structure, name): 1703 1704 """ 1705 Find for the given 'structure' all attributes for the given 'name', visiting 1706 base classes where appropriate and returning the attributes in order of 1707 descending precedence for all possible base classes. 1708 1709 The elements in the result list are 2-tuples which contain the attribute and 1710 the structure involved in accessing the attribute. 1711 """ 1712 1713 # First attempt to search the instance/class namespace. 1714 1715 try: 1716 l = structure.namespace.load(name) 1717 attributes = [] 1718 for attribute in l: 1719 attributes.append((attribute, structure)) 1720 1721 # If that does not work, attempt to investigate any class or base classes. 1722 1723 except KeyError: 1724 attributes = [] 1725 1726 # Investigate any instance's implementing class. 1727 1728 if isinstance(structure, Instance): 1729 for attr in structure.namespace.load("__class__"): 1730 cls = attr.type 1731 l = get_attributes(cls, name) 1732 combine(attributes, l) 1733 1734 # Investigate any class's base classes. 1735 1736 elif isinstance(structure, Class): 1737 1738 # If no base classes exist, return an indicator that no attribute 1739 # exists. 1740 1741 if not structure.base_refs: 1742 return [(None, structure)] 1743 1744 # Otherwise, find all possible base classes. 1745 1746 for base_refs in structure.base_refs: 1747 base_attributes = [] 1748 1749 # For each base class, find attributes either in the base 1750 # class or its own base classes. 1751 1752 for base_ref in base_refs: 1753 l = get_attributes(base_ref, name) 1754 combine(base_attributes, l) 1755 1756 combine(attributes, base_attributes) 1757 1758 return attributes 1759 1760 def get_attributes(structure, name): 1761 1762 """ 1763 Return all possible attributes for the given 'structure' having the given 1764 'name', wrapping each attribute in an Attribute object which includes 1765 context information for the attribute access. 1766 1767 The elements in the result list are 2-tuples which contain the attribute and 1768 the structure involved in accessing the attribute. 1769 """ 1770 1771 if isinstance(structure, Attribute): 1772 structure = structure.type 1773 results = [] 1774 for attribute, accessor in find_attributes(structure, name): 1775 1776 # Detect class attribute access via instances. 1777 1778 if attribute is not None and isinstance(structure, Instance) and isinstance(accessor, Class): 1779 attribute = accessor.get_attribute_for_instance(attribute, structure) 1780 1781 # Produce an attribute with the appropriate context. 1782 1783 if attribute is not None and isinstance(structure, Structure): 1784 results.append((Attribute(structure, attribute.type), accessor)) 1785 else: 1786 results.append((attribute, accessor)) 1787 1788 return results 1789 1790 def prompt(vars): 1791 try: 1792 while 1: 1793 s = raw_input("> ") 1794 print eval(s) 1795 except EOFError: 1796 pass 1797 1798 # Convenience functions. 1799 1800 def load(name, builtins=None, module_name=None, importer=None, no_annotate=0): 1801 1802 """ 1803 Load the module with the given 'name' (which may be a full module path), 1804 using the optional 'builtins' to resolve built-in names, and using the 1805 optional 'importer' to provide a means of finding and loading modules. 1806 """ 1807 1808 module = simplify.simplify(name, builtins is None, module_name) 1809 fixnames.fix(module, builtins) 1810 if not no_annotate: 1811 annotate(module, builtins, importer) 1812 return module 1813 1814 def annotate(module, builtins=None, importer=None): 1815 1816 """ 1817 Annotate the given 'module', also employing the optional 'builtins' module, 1818 if specified. If the optional 'importer' is given, use that to find and load 1819 modules. 1820 """ 1821 1822 annotator = Annotator(importer) 1823 if builtins is not None: 1824 annotator.process(module, builtins) 1825 else: 1826 annotator.process(module) 1827 1828 # vim: tabstop=4 expandtab shiftwidth=4