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 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 raises = set() 605 non_accesses = [] 606 accesses = {} 607 608 # For each expression type... 609 610 for attr in self.namespace.types: 611 612 # Find types for the named attribute. 613 614 attributes = get_attributes(attr.type, loadattr.name) 615 616 # Where no attributes exist... 617 618 if not attributes: 619 620 # Register new invalid accesses and mark a possible exception. 621 622 if not attr in non_accesses: 623 non_accesses.append(attr) 624 exc = self.get_builtin_instances(loadattr, "AttributeError") 625 raises.update(exc) 626 self.namespace.raises.update(exc) 627 628 # Revoke this type from any name involved. 629 630 self._prune_non_accesses(loadattr.expr, attr) 631 632 # For each type found... 633 634 for attribute, accessor in attributes: 635 636 # For actual attributes, register the type and remember the 637 # access. 638 639 if attribute is not None: 640 types.add(attribute) 641 if not accesses.has_key(attr.type): 642 accesses[attr.type] = [] 643 if not (attribute, accessor) in accesses[attr.type]: 644 accesses[attr.type].append((attribute, accessor)) 645 646 # Otherwise, register new invalid accesses and note a possible 647 # exception. 648 649 else: 650 if not attr in non_accesses: 651 non_accesses.append(attr) 652 exc = self.get_builtin_instances(loadattr, "AttributeError") 653 raises.update(exc) 654 self.namespace.raises.update(exc) 655 656 # Revoke this type from any name involved. 657 658 self._prune_non_accesses(loadattr.expr, attr) 659 660 if not types: 661 print "No attribute found for", loadattr.name, "given", self.namespace.types 662 663 # Remember the result types. 664 665 self.namespace.set_types(types) 666 loadattr.non_accesses = non_accesses 667 loadattr.accesses = accesses 668 loadattr.raises = raises 669 self.annotate(loadattr) 670 671 def _prune_non_accesses(self, expr, attr): 672 673 """ 674 Prune type information from 'expr' where the given 'attr' has been 675 shown to be a non-access. 676 """ 677 678 if isinstance(expr, LoadName): 679 self.namespace.revoke(expr.name, attr) 680 elif isinstance(expr, LoadExc): 681 self.namespace.revoke_exception_type(attr) 682 elif isinstance(expr, LoadTemp): 683 self.namespace.revoke_temp_type(getattr(expr, "index", None), attr) 684 685 # LoadAttr cannot be pruned since this might unintentionally prune 686 # legitimate types from other applications of the referenced type, it 687 # almost certainly doesn't take "concurrent" mutation into 688 # consideration (where in a running program, the pruned type is actually 689 # reintroduced, making the pruning invalid), and there is no easy way of 690 # preserving the meaning of a namespace without either creating lots of 691 # specialised instances, and even then... 692 693 #elif isinstance(expr, LoadAttr): 694 # for expr_attr in expr.expr.types: 695 # if hasattr(expr_attr.type, "namespace"): 696 # expr_attr.type.namespace.revoke(expr.name, attr) 697 698 def visitLoadExc(self, loadexc): 699 700 """ 701 Process the 'loadexc' node, discovering the possible exception types 702 raised. 703 """ 704 705 self.namespace.set_types(self.namespace.raises) 706 self.annotate(loadexc) 707 708 def visitLoadName(self, loadname): 709 710 """ 711 Process the 'loadname' node, processing the name information on the node 712 to determine which types are involved with the name. 713 """ 714 715 self.namespace.set_types(self.namespace.load(loadname.name)) 716 self.annotate(loadname) 717 718 def visitLoadRef(self, loadref): 719 720 """ 721 Process the 'loadref' node, obtaining type information about the 722 reference stated on the node. 723 """ 724 725 self.namespace.set_types(set([Attribute(None, loadref.ref)])) 726 self.annotate(loadref) 727 728 def visitLoadTemp(self, loadtemp): 729 730 """ 731 Process the 'loadtemp' node, obtaining type information about the 732 temporary variable accessed, and removing variable information where the 733 'release' attribute has been set on the node. 734 """ 735 736 index = getattr(loadtemp, "index", None) 737 try: 738 if getattr(loadtemp, "release", 0): 739 self.namespace.set_types(self.namespace.temp[index].pop()) 740 else: 741 self.namespace.set_types(self.namespace.temp[index][-1]) 742 except KeyError: 743 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 744 self.annotate(loadtemp) 745 746 def visitMakeTuple(self, maketuple): 747 748 """ 749 Process the 'maketuple' node and its contents. 750 """ 751 752 # Get a tuple and populate it with type information for the contents. 753 754 tuples = self.get_builtin_instances(maketuple, "tuple") 755 756 # NOTE: This is dependent on the tuple definition in the builtins. 757 758 for node in maketuple.nodes: 759 self.dispatch(node) 760 for t in tuples: 761 t.type.namespace.add("value", self.namespace.types) 762 763 self.namespace.set_types(tuples) 764 self.annotate(maketuple) 765 766 def visitModule(self, module): 767 768 """ 769 Process the 'module' and its contents. 770 """ 771 772 self.dispatches(module.code) 773 774 def visitNot(self, not_): 775 776 "Process the 'not_' node and its expression." 777 778 self.dispatch(not_.expr) 779 780 def visitPass(self, pass_): 781 782 "Leave the 'pass_' node unprocessed." 783 784 pass 785 786 def visitRaise(self, raise_): 787 788 """ 789 Process the 'raise_' node, processing any traceback information along 790 with the raised exception expression, converting the node into a kind of 791 invocation where the expression is found not to be an invocation itself. 792 This node affects the namespace, adding exception types to the list of 793 those raised in the namespace. 794 """ 795 796 if getattr(raise_, "traceback", None) is not None: 797 self.dispatch(raise_.traceback) 798 self.dispatch(raise_.expr) 799 800 # Handle bare name exceptions by converting any classes to instances. 801 802 if not isinstance(raise_.expr, InvokeFunction): 803 raise_.pos_args = [] 804 raise_.kw_args = {} 805 raise_.star = None 806 raise_.dstar = None 807 types = set() 808 for attr in self.namespace.types: 809 if isinstance(attr.type, Class): 810 self._visitInvoke(raise_, [attr], have_args=0) 811 types.update(self.namespace.types) 812 else: 813 types = self.namespace.types 814 815 self.namespace.raises.update(types) 816 817 def visitReleaseTemp(self, releasetemp): 818 819 """ 820 Process the 'releasetemp' node, removing temporary variable information 821 from the current namespace. 822 """ 823 824 index = getattr(releasetemp, "index", None) 825 try: 826 self.namespace.temp[index].pop() 827 except KeyError: 828 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 829 except IndexError: 830 pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index 831 832 def visitResetExc(self, resetexc): 833 self.namespace.raises = set() 834 835 def visitReturn(self, return_): 836 837 """ 838 Process the 'return_' node, processing any expression and obtaining type 839 information to be accumulated in the current namespace's list of return 840 types. A snapshot of the namespace is taken for the purposes of 841 reconciling or merging namespaces where subprograms actually share 842 locals with their callers. 843 """ 844 845 if hasattr(return_, "expr"): 846 self.dispatch(return_.expr) 847 self.namespace.returns.update(self.namespace.types) 848 self.annotate(return_) 849 self.namespace.snapshot() 850 851 visitReturnFromBlock = visitReturn 852 visitReturnFromFunction = visitReturn 853 854 def visitStoreAttr(self, storeattr): 855 856 """ 857 Process the 'storeattr' node, processing the expression and target, and 858 using the type information obtained to build records of legitimate 859 writes to the stated attribute, along with "impossible" non-writes to 860 the attribute. 861 """ 862 863 self.dispatch(storeattr.expr) 864 expr = self.namespace.types 865 self.dispatch(storeattr.lvalue) 866 writes = {} 867 non_writes = [] 868 for attr in self.namespace.types: 869 # NOTE: Impose "atomic" constraints on certain types. 870 if attr is None: 871 if not attr in non_writes: 872 non_writes.append(attr) 873 continue 874 attr.type.namespace.add(storeattr.name, expr) 875 writes[attr.type] = attr.type.namespace.load(storeattr.name) 876 if not writes: 877 print "Unable to store attribute", storeattr.name, "given", self.namespace.types 878 storeattr.writes = writes 879 storeattr.non_writes = non_writes 880 881 def visitStoreName(self, storename): 882 883 """ 884 Process the 'storename' node, processing the expression on the node and 885 associating the type information obtained with the stated name in the 886 current namespace. 887 """ 888 889 self.dispatch(storename.expr) 890 self.namespace.store(storename.name, self.namespace.types) 891 self.annotate(storename) 892 893 def visitStoreTemp(self, storetemp): 894 895 """ 896 Process the 'storetemp' node, processing the expression on the node and 897 associating the type information obtained with a temporary variable in 898 the current namespace. 899 """ 900 901 self.dispatch(storetemp.expr) 902 index = getattr(storetemp, "index", None) 903 if not self.namespace.temp.has_key(index): 904 self.namespace.temp[index] = [] 905 self.namespace.temp[index].append(self.namespace.types) 906 907 def visitSubprogram(self, subprogram): 908 909 """ 910 Process the 'subprogram' node, processing its contents (a group of nodes 911 comprising the subprogram). 912 """ 913 914 self.dispatches(subprogram.code) 915 916 def visitTry(self, try_): 917 918 """ 919 Process the 'try_' node, processing the body clause in its own namespace 920 derived from the current namespace, processing any handler clause using 921 the namespace information accumulated in the body, and processing any 922 else and finally clauses, attempting to supply each with appropriate 923 namespace information. 924 """ 925 926 is_module = self.namespace is self.module.namespace 927 928 self.dispatches(try_.body) 929 930 # Save the namespace from the body. 931 932 body_namespace = Namespace() 933 body_namespace.merge_namespace(self.namespace) 934 935 # Process the handler. 936 937 if hasattr(try_, "handler"): 938 self.dispatches(try_.handler) 939 940 # Save the namespace from the handler. 941 942 handler_namespace = Namespace() 943 handler_namespace.merge_namespace(self.namespace) 944 945 # Remember the raised exceptions encountered so far. 946 947 raises = self.namespace.raises 948 949 # Process the else clause. 950 951 if hasattr(try_, "else_"): 952 953 # Restore the body namespace for the else clause. 954 955 self.namespace = body_namespace 956 if is_module: 957 self.module.namespace = self.namespace 958 959 # Empty the raised exceptions for the else clause. 960 961 self.namespace.raises = set() 962 self.dispatches(try_.else_) 963 self.namespace.raises = raises 964 965 # Merge the namespaces. 966 967 self.namespace = Namespace() 968 if is_module: 969 self.module.namespace = self.namespace 970 self.namespace.merge_namespace(body_namespace) 971 self.namespace.merge_namespace(handler_namespace) 972 973 # Process the finally clause, if any. 974 975 self.dispatches(try_.finally_) 976 977 def visitYield(self, yield_): 978 raise NotImplementedError, "The yield statement is not currently supported." 979 980 # Utility methods. 981 982 def get_builtin_instances(self, node, name): 983 return set([Attribute(None, self.new_instance(node, attr.type)) for attr in self.builtins.namespace[name]]) 984 985 def new_instance(self, node, type): 986 987 "For the given 'node', obtain an instance from the given 'type'." 988 989 if not type.has_instance(node): 990 instance = Instance() 991 instance.namespace = Namespace() 992 instance.namespace.store("__class__", set([Attribute(None, type)])) 993 type.add_instance(node, instance) 994 else: 995 instance = type.get_instance(node) 996 997 return instance 998 999 def invoke_subprogram(self, invoke, attribute): 1000 1001 """ 1002 Invoke using the given 'invoke' node the subprogram represented by the 1003 given 'attribute'. 1004 """ 1005 1006 # Test for context information, making it into a real attribute. 1007 1008 if attribute.context is not None: 1009 context = Attribute(None, attribute.context) 1010 target = attribute.type 1011 else: 1012 context = None 1013 target = attribute.type 1014 1015 # Test to see if anything has changed. 1016 1017 if hasattr(invoke, "syscount") and invoke.syscount.has_key(target) and invoke.syscount[target] == self.system.count: 1018 return 1019 1020 # Remember the state of the system. 1021 1022 else: 1023 if not hasattr(invoke, "syscount"): 1024 invoke.syscount = {} 1025 invoke.syscount[target] = self.system.count 1026 1027 # Provide the correct namespace for the invocation. 1028 # This may be a "shared" namespace... 1029 1030 if getattr(invoke, "share_locals", 0): 1031 namespace = Namespace() 1032 namespace.merge_namespace(self.namespace, everything=0) 1033 using_module_namespace = self.namespace is self.module.namespace 1034 1035 # Or it may be a structure... 1036 1037 elif getattr(target, "structure", None): 1038 namespace = Namespace() 1039 using_module_namespace = 0 1040 1041 # Or it may be a new namespace populated with the supplied parameters. 1042 1043 else: 1044 items = self.make_items(invoke, target, context) 1045 namespace = Namespace() 1046 namespace.merge_items(items) 1047 using_module_namespace = 0 1048 1049 # NOTE: Avoid PEP 227 (nested scopes) whilst permitting references to a 1050 # NOTE: subprogram within itself. Do not define the name of the function 1051 # NOTE: within a method definition. 1052 1053 if getattr(target, "name", None) is not None and not getattr(target, "is_method", 0): 1054 namespace.store(target.name, set([Attribute(None, target)])) 1055 1056 # Process the subprogram. 1057 1058 self.process_node(target, namespace, using_module_namespace) 1059 1060 # NOTE: Improve and verify this. 1061 # If the invocation returns a value, acquire the return types. 1062 1063 if getattr(target, "returns_value", 0): 1064 self.namespace.set_types(target.returns) 1065 self.annotate(invoke) 1066 1067 # If it is a normal block, merge the locals. 1068 # This can happen in addition to the above because for things like 1069 # logical expressions, the namespace can be modified whilst values are 1070 # returned as results. 1071 1072 if getattr(invoke, "share_locals", 0): 1073 self.namespace.reset() 1074 1075 # Merge the locals snapshots. 1076 1077 for locals in target.return_locals: 1078 1079 # For blocks returning values (such as operations), do not merge 1080 # snapshots or results. 1081 1082 if getattr(target, "returns_value", 0): 1083 self.namespace.merge_namespace(locals, everything=0) 1084 1085 # For blocks not returning values (such as loops), merge 1086 # snapshots and results since they contain details of genuine 1087 # returns. 1088 1089 else: 1090 self.namespace.merge_namespace(locals) 1091 1092 # Incorporate any raised exceptions. 1093 1094 if not hasattr(invoke, "raises"): 1095 invoke.raises = set() 1096 invoke.raises.update(target.raises) 1097 self.namespace.raises.update(target.raises) 1098 1099 def process_args(self, invocation): 1100 1101 """ 1102 Process the arguments associated with an 'invocation'. Return whether 1103 any arguments were processed. 1104 """ 1105 1106 self.dispatches(invocation.pos_args) 1107 self.dispatch_dict(invocation.kw_args) 1108 1109 # Get type information for star and dstar arguments. 1110 1111 if invocation.star is not None: 1112 param, default = invocation.star 1113 self.dispatch(default) 1114 invocation.star = param, default 1115 1116 if invocation.dstar is not None: 1117 param, default = invocation.dstar 1118 self.dispatch(default) 1119 invocation.dstar = param, default 1120 1121 if invocation.pos_args or invocation.kw_args or invocation.star or invocation.dstar: 1122 return 1 1123 else: 1124 return 0 1125 1126 def make_items(self, invocation, subprogram, context): 1127 1128 """ 1129 Make an items mapping for the 'invocation' of the 'subprogram' using the 1130 given 'context' (which may be None). 1131 """ 1132 1133 # NOTE: Support class methods! 1134 1135 if context is not None and isinstance(context.type, Instance): 1136 pos_args = [Self(context)] + invocation.pos_args 1137 else: 1138 pos_args = invocation.pos_args 1139 1140 # Duplicate the keyword arguments - we remove them in processing below. 1141 1142 kw_args = {} 1143 kw_args.update(invocation.kw_args) 1144 1145 # Sort the arguments into positional and keyword arguments. 1146 1147 params = subprogram.params 1148 items = [] 1149 star_args = [] 1150 1151 # Match each positional argument, taking excess arguments as star args. 1152 1153 for arg in pos_args: 1154 if params: 1155 param, default = params[0] 1156 if arg is None: 1157 arg = default 1158 if hasattr(arg, "types"): 1159 items.append((param, arg.types)) 1160 else: 1161 items.append((param, set())) # Annotation has not succeeded. 1162 params = params[1:] 1163 else: 1164 star_args.append(arg) 1165 1166 # Collect the remaining defaults. 1167 1168 while params: 1169 param, default = params[0] 1170 if kw_args.has_key(param): 1171 arg = kw_args[param] 1172 del kw_args[param] 1173 elif default is not None: 1174 self.dispatch(default) 1175 arg = default 1176 else: 1177 raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param) 1178 if hasattr(arg, "types"): 1179 items.append((param, arg.types)) 1180 else: 1181 items.append((param, set())) # Annotation has not succeeded. 1182 params = params[1:] 1183 1184 dstar_args = kw_args.items() 1185 1186 # Construct temporary objects. 1187 1188 if star_args: 1189 star_invocation = self.make_star_args(invocation, subprogram, star_args) 1190 self.dispatch(star_invocation) 1191 star_types = star_invocation.types 1192 else: 1193 star_types = None 1194 1195 if dstar_args: 1196 dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args) 1197 self.dispatch(dstar_invocation) 1198 dstar_types = dstar_invocation.types 1199 else: 1200 dstar_types = None 1201 1202 # NOTE: Merge the objects properly. 1203 1204 star_types = star_types or invocation.star and invocation.star.types 1205 dstar_types = dstar_types or invocation.dstar and invocation.dstar.types 1206 1207 # Add star and dstar. 1208 1209 if star_types is not None: 1210 if subprogram.star is not None: 1211 param, default = subprogram.star 1212 items.append((param, star_types)) 1213 else: 1214 raise AnnotationMessage, "Invocation provides unwanted *args." 1215 elif subprogram.star is not None: 1216 param, default = subprogram.star 1217 if not hasattr(default, "types"): 1218 subprogram.star = param, self.dispatch(default) # NOTE: Review reprocessing. 1219 items.append((param, default.types)) 1220 1221 if dstar_types is not None: 1222 if subprogram.dstar is not None: 1223 param, default = subprogram.dstar 1224 items.append((param, dstar_types)) 1225 else: 1226 raise AnnotationMessage, "Invocation provides unwanted **args." 1227 elif subprogram.dstar is not None: 1228 param, default = subprogram.dstar 1229 if not hasattr(default, "types"): 1230 subprogram.dstar = param, self.dispatch(default) # NOTE: Review reprocessing. 1231 items.append((param, default.types)) 1232 1233 # Record the parameter types. 1234 1235 self.annotate_parameters(subprogram, items) 1236 return subprogram.paramtypes.items() 1237 1238 def make_star_args(self, invocation, subprogram, star_args): 1239 1240 "Make a subprogram which initialises a list containing 'star_args'." 1241 1242 if not hasattr(invocation, "stars"): 1243 invocation.stars = {} 1244 1245 if not invocation.stars.has_key(subprogram.full_name()): 1246 instance = getattr(invocation, "instance", None) 1247 1248 code = [ 1249 Return( 1250 instance=instance, 1251 expr=MakeTuple( 1252 instance=instance, 1253 nodes=star_args 1254 ) 1255 ) 1256 ] 1257 1258 new_subprogram = Subprogram( 1259 instance=instance, 1260 name=None, 1261 returns_value=1, 1262 params=[], 1263 star=None, 1264 dstar=None, 1265 code=code 1266 ) 1267 1268 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 1269 1270 invocation.stars[subprogram.full_name()] = InvokeRef( 1271 invocation.original, 1272 instance=instance, 1273 produces_result=1, 1274 ref=new_subprogram 1275 ) 1276 1277 return invocation.stars[subprogram.full_name()] 1278 1279 def make_dstar_args(self, invocation, subprogram, dstar_args): 1280 1281 """ 1282 Make a subprogram which initialises a dictionary built from the given 1283 'dstar_args'. 1284 """ 1285 1286 if not hasattr(invocation, "dstars"): 1287 invocation.dstars = {} 1288 1289 if not invocation.dstars.has_key(subprogram.full_name()): 1290 instance = getattr(invocation, "instance", None) 1291 1292 code=[ 1293 StoreTemp( 1294 instance=instance, 1295 expr=InvokeFunction( 1296 invocation.original, 1297 instance=instance, 1298 expr=LoadAttr( 1299 instance=instance, 1300 expr=LoadRef( 1301 instance=instance, 1302 ref=self.builtins 1303 ), 1304 name="dict", 1305 nstype="module", 1306 ) 1307 ) 1308 ) 1309 ] 1310 1311 for arg, value in dstar_args: 1312 1313 # NOTE: Constant not added to table. 1314 1315 constant = Constant(name=repr(arg), value=arg) 1316 code += [ 1317 StoreTemp( 1318 instance=instance, 1319 expr=InvokeFunction( 1320 instance=instance, 1321 expr=LoadName( 1322 instance=instance, 1323 name=constant.typename 1324 ) 1325 ), 1326 index="const" 1327 ), 1328 InvokeFunction( 1329 invocation.original, 1330 instance=instance, 1331 expr=LoadAttr( 1332 instance=instance, 1333 expr=LoadTemp( 1334 instance=instance 1335 ), 1336 name="__setitem__" 1337 ), 1338 args=[ 1339 LoadTemp( 1340 instance=instance, 1341 index="const", 1342 release=1 1343 ), 1344 value 1345 ] 1346 ) 1347 ] 1348 1349 code += [ 1350 Return( 1351 instance=instance, 1352 expr=LoadTemp( 1353 instance=instance, 1354 release=1 1355 ) 1356 ) 1357 ] 1358 1359 new_subprogram = Subprogram( 1360 instance=instance, 1361 name=None, 1362 returns_value=1, 1363 params=[], 1364 star=None, 1365 dstar=None, 1366 code=code 1367 ) 1368 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 1369 1370 invocation.dstars[subprogram.full_name()] = InvokeRef( 1371 invocation.original, 1372 instance=instance, 1373 produces_result=1, 1374 ref=new_subprogram 1375 ) 1376 1377 return invocation.dstars[subprogram.full_name()] 1378 1379 # Namespace-related abstractions. 1380 1381 class Namespace: 1382 1383 """ 1384 A local namespace which may either relate to a genuine set of function 1385 locals or the initialisation of a structure or module. 1386 """ 1387 1388 def __init__(self): 1389 1390 """ 1391 Initialise the namespace with a mapping of local names to possible 1392 types, a list of return values and of possible returned local 1393 namespaces. The namespace also tracks the "current" types and a mapping 1394 of temporary value names to types. 1395 """ 1396 1397 self.names = {} 1398 self.returns = set() 1399 self.return_locals = set() 1400 self.raises = set() 1401 self.temp = {} 1402 self.types = set() 1403 1404 def set_types(self, types): 1405 1406 "Set the current collection of 'types'." 1407 1408 self.types = types.copy() 1409 1410 def add(self, name, types): 1411 1412 "Add to the entry with the given 'name' the specified 'types'." 1413 1414 if self.names.has_key(name): 1415 self.names[name].update(types) 1416 else: 1417 self.store(name, types) 1418 1419 def store(self, name, types): 1420 1421 "Store in (or associate with) the given 'name' the specified 'types'." 1422 1423 self.names[name] = types.copy() 1424 1425 __setitem__ = store 1426 1427 def load(self, name): 1428 1429 "Load the types associated with the given 'name'." 1430 1431 return self.names[name] 1432 1433 __getitem__ = load 1434 1435 def has_key(self, name): 1436 return self.names.has_key(name) 1437 1438 def revoke(self, name, type): 1439 1440 "Revoke from the entry for the given 'name' the specified 'type'." 1441 1442 new_types = self.names[name].copy() 1443 new_types.remove(type) 1444 self.names[name] = new_types 1445 1446 def revoke_exception_type(self, type): 1447 1448 "Revoke the given 'type' from the collection of exception types." 1449 1450 self.raises.remove(type) 1451 1452 def revoke_temp_type(self, index, type): 1453 1454 "Revoke from the temporary variable 'index' the given 'type'." 1455 1456 new_types = self.temp[index][-1].copy() 1457 new_types.remove(type) 1458 self.temp[index][-1] = new_types 1459 1460 def merge_namespace(self, namespace, everything=1): 1461 1462 """ 1463 Merge items from the given 'namespace' with this namespace. When the 1464 optional 'everything' parameter is set to a false value (unlike the 1465 default), return values and locals snapshots will not be copied to this 1466 namespace. 1467 """ 1468 1469 self.merge_items(namespace.names.items()) 1470 self.raises.update(namespace.raises) 1471 if everything: 1472 self.returns.update(namespace.returns) 1473 self.return_locals.update(namespace.return_locals) 1474 for name, values in namespace.temp.items(): 1475 if values: 1476 if not self.temp.has_key(name) or not self.temp[name]: 1477 self.temp[name] = [set()] 1478 self.temp[name][-1].update(values[-1]) 1479 1480 def merge_items(self, items): 1481 1482 "Merge the given 'items' with this namespace." 1483 1484 for name, types in items: 1485 self.merge(name, types) 1486 1487 def merge(self, name, types): 1488 1489 "Merge the entry for the given 'name' and 'types' with this namespace." 1490 1491 if not self.names.has_key(name): 1492 self.names[name] = types.copy() 1493 else: 1494 existing = self.names[name] 1495 existing.update(types) 1496 1497 def snapshot(self): 1498 1499 "Make a snapshot of the locals and remember them." 1500 1501 namespace = Namespace() 1502 namespace.merge_namespace(self) 1503 self.return_locals.add(namespace) 1504 1505 def reset(self): 1506 1507 "Reset a namespace in preparation for merging with returned locals." 1508 1509 self.names = {} 1510 1511 def __repr__(self): 1512 return repr(self.names) + " (temp) " + repr(self.temp) 1513 1514 class Importer: 1515 1516 "An import machine, searching for and loading modules." 1517 1518 def __init__(self, path=None): 1519 1520 """ 1521 Initialise the importer with the given search 'path' - a list of 1522 directories to search for Python modules. 1523 """ 1524 1525 self.path = path or [os.getcwd()] 1526 self.path.append(libdir) 1527 self.modules = {} 1528 1529 def find_in_path(self, name): 1530 1531 """ 1532 Find the given module 'name' in the search path, returning None where no 1533 such module could be found, or a 2-tuple from the 'find' method 1534 otherwise. 1535 """ 1536 1537 for d in self.path: 1538 m = self.find(d, name) 1539 if m: return m 1540 return None 1541 1542 def find(self, d, name): 1543 1544 """ 1545 In the directory 'd', find the given module 'name', where 'name' can 1546 either refer to a single file module or to a package. Return None if the 1547 'name' cannot be associated with either a file or a package directory, 1548 or a 2-tuple from '_find_package' or '_find_module' otherwise. 1549 """ 1550 1551 m = self._find_package(d, name) 1552 if m: return m 1553 m = self._find_module(d, name) 1554 if m: return m 1555 return None 1556 1557 def _find_module(self, d, name): 1558 1559 """ 1560 In the directory 'd', find the given module 'name', returning None where 1561 no suitable file exists in the directory, or a 2-tuple consisting of 1562 None (indicating that no package directory is involved) and a filename 1563 indicating the location of the module. 1564 """ 1565 1566 name_py = name + os.extsep + "py" 1567 filename = self._find_file(d, name_py) 1568 if filename: 1569 return None, filename 1570 return None 1571 1572 def _find_package(self, d, name): 1573 1574 """ 1575 In the directory 'd', find the given package 'name', returning None 1576 where no suitable package directory exists, or a 2-tuple consisting of 1577 a directory (indicating the location of the package directory itself) 1578 and a filename indicating the location of the __init__.py module which 1579 declares the package's top-level contents. 1580 """ 1581 1582 filename = self._find_file(d, name) 1583 if filename: 1584 init_py = "__init__" + os.path.extsep + "py" 1585 init_py_filename = self._find_file(filename, init_py) 1586 if init_py_filename: 1587 return filename, init_py_filename 1588 return None 1589 1590 def _find_file(self, d, filename): 1591 1592 """ 1593 Return the filename obtained when searching the directory 'd' for the 1594 given 'filename', or None if no actual file exists for the filename. 1595 """ 1596 1597 filename = os.path.join(d, filename) 1598 if os.path.exists(filename): 1599 return filename 1600 else: 1601 return None 1602 1603 def load(self, name, builtins, alias=None): 1604 1605 """ 1606 Load the module or package with the given 'name' and using the specified 1607 'builtins'. Return an Attribute object referencing the loaded module or 1608 package, or None if no such module or package exists. 1609 """ 1610 1611 if self.modules.has_key(name): 1612 return Attribute(None, self.modules[name]) 1613 1614 path = name.split(".") 1615 m = self.find_in_path(path[0]) 1616 if not m: 1617 return None # NOTE: Import error. 1618 d, filename = m 1619 1620 if self.modules.has_key(path[0]): 1621 top = module = self.modules[path[0]] 1622 else: 1623 top = module = self.modules[path[0]] = load(filename, builtins, path[0], self, no_annotate=1) 1624 annotate(module, builtins, self) 1625 1626 if len(path) > 1: 1627 path_so_far = path[:1] 1628 for p in path[1:]: 1629 path_so_far.append(p) 1630 m = self.find(d, p) 1631 if not m: 1632 return None # NOTE: Import error. 1633 d, filename = m 1634 module_name = ".".join(path_so_far) 1635 1636 if self.modules.has_key(module_name): 1637 submodule = self.modules[module_name] 1638 else: 1639 submodule = self.modules[module_name] = load(filename, builtins, module_name, self, no_annotate=1) 1640 annotate(submodule, builtins, self) 1641 1642 # Store the submodule within its parent module. 1643 1644 module.namespace[p] = [Attribute(None, submodule)] 1645 module = submodule 1646 1647 if alias: 1648 return Attribute(None, module) 1649 else: 1650 return Attribute(None, top) 1651 1652 def combine(target, additions): 1653 1654 """ 1655 Merge into the 'target' sequence the given 'additions', preventing duplicate 1656 items. 1657 """ 1658 1659 for addition in additions: 1660 if addition not in target: 1661 target.append(addition) 1662 1663 def find_attributes(structure, name): 1664 1665 """ 1666 Find for the given 'structure' all attributes for the given 'name', visiting 1667 base classes where appropriate and returning the attributes in order of 1668 descending precedence for all possible base classes. 1669 1670 The elements in the result list are 2-tuples which contain the attribute and 1671 the structure involved in accessing the attribute. 1672 """ 1673 1674 # First attempt to search the instance/class namespace. 1675 1676 try: 1677 l = structure.namespace.load(name) 1678 attributes = [] 1679 for attribute in l: 1680 attributes.append((attribute, structure)) 1681 1682 # If that does not work, attempt to investigate any class or base classes. 1683 1684 except KeyError: 1685 attributes = [] 1686 1687 # Investigate any instance's implementing class. 1688 1689 if isinstance(structure, Instance): 1690 for attr in structure.namespace.load("__class__"): 1691 cls = attr.type 1692 l = get_attributes(cls, name) 1693 combine(attributes, l) 1694 1695 # Investigate any class's base classes. 1696 1697 elif isinstance(structure, Class): 1698 1699 # If no base classes exist, return an indicator that no attribute 1700 # exists. 1701 1702 if not structure.base_refs: 1703 return [(None, structure)] 1704 1705 # Otherwise, find all possible base classes. 1706 1707 for base_refs in structure.base_refs: 1708 base_attributes = [] 1709 1710 # For each base class, find attributes either in the base 1711 # class or its own base classes. 1712 1713 for base_ref in base_refs: 1714 l = get_attributes(base_ref, name) 1715 combine(base_attributes, l) 1716 1717 combine(attributes, base_attributes) 1718 1719 return attributes 1720 1721 def get_attributes(structure, name): 1722 1723 """ 1724 Return all possible attributes for the given 'structure' having the given 1725 'name', wrapping each attribute in an Attribute object which includes 1726 context information for the attribute access. 1727 1728 The elements in the result list are 2-tuples which contain the attribute and 1729 the structure involved in accessing the attribute. 1730 """ 1731 1732 if isinstance(structure, Attribute): 1733 structure = structure.type 1734 results = [] 1735 for attribute, accessor in find_attributes(structure, name): 1736 1737 # Detect class attribute access via instances. 1738 1739 if attribute is not None and isinstance(structure, Instance) and isinstance(accessor, Class): 1740 attribute = accessor.get_attribute_for_instance(attribute, structure) 1741 1742 # Produce an attribute with the appropriate context. 1743 1744 if attribute is not None and isinstance(structure, Structure): 1745 results.append((Attribute(structure, attribute.type), accessor)) 1746 else: 1747 results.append((attribute, accessor)) 1748 1749 return results 1750 1751 def prompt(vars): 1752 try: 1753 while 1: 1754 s = raw_input("> ") 1755 print eval(s, vars) 1756 except EOFError: 1757 pass 1758 1759 # Convenience functions. 1760 1761 def load(name, builtins=None, module_name=None, importer=None, no_annotate=0): 1762 1763 """ 1764 Load the module with the given 'name' (which may be a full module path), 1765 using the optional 'builtins' to resolve built-in names, and using the 1766 optional 'importer' to provide a means of finding and loading modules. 1767 """ 1768 1769 module = simplify.ast.simplify(name, builtins is None, module_name) 1770 simplify.fixnames.fix(module, builtins) 1771 if not no_annotate: 1772 annotate(module, builtins, importer) 1773 return module 1774 1775 def annotate(module, builtins=None, importer=None): 1776 1777 """ 1778 Annotate the given 'module', also employing the optional 'builtins' module, 1779 if specified. If the optional 'importer' is given, use that to find and load 1780 modules. 1781 """ 1782 1783 annotator = Annotator(importer) 1784 if builtins is not None: 1785 annotator.process(module, builtins) 1786 else: 1787 annotator.process(module) 1788 1789 # vim: tabstop=4 expandtab shiftwidth=4