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