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