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 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 annotate function: 28 29 annotate(module, builtins) 30 31 The more complicated approach involves obtaining an Annotator: 32 33 annotator = Annotator() 34 35 Then, processing an existing module with it: 36 37 annotator.process(module) 38 39 If a module containing built-in classes and functions has already been 40 annotated, such a module should be passed in as an additional argument: 41 42 annotator.process(module, builtins) 43 """ 44 45 from simplified import * 46 import compiler 47 48 class System: 49 50 """ 51 A class maintaining the state of the annotation system. When the system 52 counter can no longer be incremented by any annotation operation, the 53 system may be considered stable and fully annotated. 54 """ 55 56 def __init__(self): 57 self.count = 0 58 59 def init(self, node): 60 if not hasattr(node, "types"): 61 node.types = [] 62 63 def annotate(self, node, types): 64 self.init(node) 65 self.combine(node.types, types) 66 67 def combine(self, target, types): 68 for type in types: 69 if type not in target: 70 target.append(type) 71 self.count += 1 72 73 system = System() 74 75 # Exceptions. 76 77 class AnnotationError(SimplifiedError): 78 79 "An error in the annotation process." 80 81 pass 82 83 class AnnotationMessage(Exception): 84 85 "A lesser annotation error." 86 87 pass 88 89 # Annotation. 90 91 class Annotator(Visitor): 92 93 """ 94 The type annotator which traverses the program nodes, typically depth-first, 95 and maintains a record of the current set of types applying to the currently 96 considered operation. Such types are also recorded on the nodes, and a 97 special "system" record is maintained to monitor the level of annotation 98 activity with a view to recognising when no more annotations are possible. 99 100 Throughout the annotation activity, type information consists of lists of 101 Attribute objects where such objects retain information about the context of 102 the type (since a value in the program may be associated with an object or 103 class) and the actual type of the value being manipulated. Upon accessing 104 attribute information on namespaces, additional accessor information is also 105 exchanged - this provides a means of distinguishing between the different 106 types possible when the means of constructing the namespace may depend on 107 run-time behaviour. 108 """ 109 110 def __init__(self): 111 112 "Initialise the visitor." 113 114 Visitor.__init__(self) 115 self.system = system 116 117 # Satisfy visitor issues. 118 119 self.visitor = self 120 121 def process(self, module, builtins=None): 122 123 """ 124 Process the given 'module', using the optional 'builtins' to access 125 built-in classes and functions. 126 """ 127 128 self.subprograms = [] 129 self.current_subprograms = [] 130 self.current_namespaces = [] 131 self.namespace = None 132 self.module = module 133 134 # Give constants their own namespace. 135 136 for value, constant in module.simplifier.constants.items(): 137 constant.namespace = Namespace() 138 139 # Process the module, supplying builtins if possible. 140 141 self.builtins = builtins 142 self.global_namespace = Namespace() 143 144 if builtins is not None: 145 self.builtins_namespace = builtins.namespace 146 else: 147 self.builtins_namespace = self.global_namespace 148 149 return self.process_node(module, self.global_namespace) 150 151 def process_node(self, node, locals): 152 153 """ 154 Process a subprogram or module 'node', indicating the initial 'locals'. 155 Return an annotated subprogram or module. Note that this method may 156 mutate nodes in the original program. 157 """ 158 159 # Record the current subprogram and namespace. 160 161 self.current_subprograms.append(node) 162 163 # Determine the namespace. 164 165 self.current_namespaces.append(self.namespace) 166 self.namespace = locals 167 168 # Add namespace details to any structure involved. 169 170 if getattr(node, "structure", None) is not None: 171 node.structure.namespace = Namespace() 172 173 # Initialise bases where appropriate. 174 175 if hasattr(node.structure, "bases"): 176 base_refs = [] 177 for base in node.structure.bases: 178 self.dispatch(base) 179 base_refs.append(self.namespace.types) 180 node.structure.base_refs = base_refs 181 182 # Dispatch to the code itself. 183 184 node.namespace = self.namespace 185 result = self.dispatch(node) 186 result.namespace = self.namespace 187 188 # Obtain the return values. 189 190 self.last_returns = self.namespace.returns 191 self.last_raises = self.namespace.raises 192 self.returned_locals = self.namespace.return_locals 193 194 # Restore the previous subprogram and namespace. 195 196 self.namespace = self.current_namespaces.pop() 197 self.current_subprograms.pop() 198 199 return result 200 201 def annotate(self, node, types=None): 202 203 """ 204 Annotate the given 'node' in the system, using either the optional 205 'types' or the namespace's current type information. 206 """ 207 208 self.system.annotate(node, types or self.namespace.types) 209 210 def annotate_parameters(self, node, items): 211 212 """ 213 Annotate the given 'node' using the given 'items' and updating the 214 system's annotation counter. 215 """ 216 217 if not hasattr(node, "paramtypes"): 218 node.paramtypes = {} 219 220 for param, types in items: 221 if not node.paramtypes.has_key(param): 222 node.paramtypes[param] = [] 223 self.system.combine(node.paramtypes[param], types) 224 225 # Visitor methods. 226 227 def default(self, node): 228 229 """ 230 Process the given 'node', given that it does not have a specific 231 handler. 232 """ 233 234 raise AnnotationMessage, "Node '%s' not supported." % node 235 236 def dispatch(self, node, *args): 237 try: 238 return Visitor.dispatch(self, node, *args) 239 except AnnotationError, exc: 240 exc.add(node) 241 raise 242 except AnnotationMessage, exc: 243 raise AnnotationError(exc, node) 244 245 # Program structure/control-flow. 246 247 def visitAssign(self, assign): 248 assign.code = self.dispatches(assign.code) 249 return assign 250 251 def visitConditional(self, conditional): 252 253 # Conditionals keep local namespace changes isolated. 254 # With Return nodes inside the body/else sections, the changes are 255 # communicated to the caller. 256 257 is_module = self.namespace is self.module.namespace 258 259 # Where the test is closely associated with the body, save the namespace 260 # before entering the test. 261 262 if conditional.isolate_test: 263 saved_namespace = self.namespace 264 self.namespace = Namespace() 265 if is_module: 266 self.module.namespace = self.namespace 267 self.namespace.merge_namespace(saved_namespace) 268 269 conditional.test = self.dispatch(conditional.test) 270 271 # Where the test may affect the body and the else clause, save the 272 # namespace after processing the test. 273 274 if not conditional.isolate_test: 275 saved_namespace = self.namespace 276 self.namespace = Namespace() 277 if is_module: 278 self.module.namespace = self.namespace 279 self.namespace.merge_namespace(saved_namespace) 280 281 # Process the body clause. 282 283 conditional.body = self.dispatches(conditional.body) 284 body_namespace = self.namespace 285 286 # Use the saved namespace as a template for the else clause. 287 288 self.namespace = Namespace() 289 if is_module: 290 self.module.namespace = self.namespace 291 self.namespace.merge_namespace(saved_namespace) 292 293 # Process the else clause. 294 295 conditional.else_ = self.dispatches(conditional.else_) 296 else_namespace = self.namespace 297 298 # Merge the body and else namespaces. 299 300 self.namespace = Namespace() 301 if is_module: 302 self.module.namespace = self.namespace 303 self.namespace.merge_namespace(body_namespace) 304 self.namespace.merge_namespace(else_namespace) 305 306 return conditional 307 308 def visitModule(self, module): 309 module.code = self.dispatches(module.code) 310 return module 311 312 def visitPass(self, pass_): 313 return pass_ 314 315 def visitSubprogram(self, subprogram): 316 subprogram.code = self.dispatches(subprogram.code) 317 return subprogram 318 319 def visitTry(self, try_): 320 is_module = self.namespace is self.module.namespace 321 322 try_.body = self.dispatches(try_.body) 323 324 # Save the namespace from the body. 325 326 body_namespace = Namespace() 327 body_namespace.merge_namespace(self.namespace) 328 329 # Process the handler. 330 331 if hasattr(try_, "handler"): 332 try_.handler = self.dispatches(try_.handler) 333 334 # Save the namespace from the handler. 335 336 handler_namespace = Namespace() 337 handler_namespace.merge_namespace(self.namespace) 338 339 # Remember the raised exceptions encountered so far. 340 341 raises = self.namespace.raises 342 343 # Process the else clause. 344 345 if hasattr(try_, "else_"): 346 347 # Restore the body namespace for the else clause. 348 349 self.namespace = body_namespace 350 if is_module: 351 self.module.namespace = self.namespace 352 353 # Empty the raised exceptions for the else clause. 354 355 self.namespace.raises = [] 356 try_.else_ = self.dispatches(try_.else_) 357 self.namespace.raises = raises 358 359 # Merge the namespaces. 360 361 self.namespace = Namespace() 362 if is_module: 363 self.module.namespace = self.namespace 364 self.namespace.merge_namespace(body_namespace) 365 self.namespace.merge_namespace(handler_namespace) 366 367 # Process the finally clause, if any. 368 369 try_.finally_ = self.dispatches(try_.finally_) 370 return try_ 371 372 # Namespace operations. 373 374 def visitCheckExc(self, checkexc): 375 checkexc.expr = self.dispatch(checkexc.expr) 376 expr_types = self.namespace.types 377 choice_types = [] 378 choices = [] 379 for choice in checkexc.choices: 380 choices.append(self.dispatch(choice)) 381 choice_types += self.namespace.types 382 for expr_type in expr_types: 383 if expr_type.type.get_class() not in choice_types: 384 self._prune_non_accesses(checkexc.expr, expr_type) 385 return checkexc 386 387 def visitLoadAttr(self, loadattr): 388 loadattr.expr = self.dispatch(loadattr.expr) 389 types = [] 390 non_accesses = [] 391 accesses = {} 392 for attr in self.namespace.types: 393 attributes = get_attributes(attr.type, loadattr.name) 394 if not attributes: 395 if not attr.type in non_accesses: 396 non_accesses.append(attr) 397 398 # Revoke this type from any name involved. 399 400 self._prune_non_accesses(loadattr.expr, attr) 401 402 for attribute, accessor in attributes: 403 if attribute is not None: 404 types.append(attribute) 405 if not accesses.has_key(attr.type): 406 accesses[attr.type] = [] 407 if not (attribute, accessor) in accesses[attr.type]: 408 accesses[attr.type].append((attribute, accessor)) 409 else: 410 if not attr in non_accesses: 411 non_accesses.append(attr) 412 413 # Revoke this type from any name involved. 414 415 self._prune_non_accesses(loadattr.expr, attr) 416 417 if not types: 418 print "No attribute found for", loadattr.name, "given", self.namespace.types 419 self.namespace.set_types(types) 420 loadattr.non_accesses = non_accesses 421 loadattr.accesses = accesses 422 self.annotate(loadattr) 423 return loadattr 424 425 def _prune_non_accesses(self, expr, attr): 426 if isinstance(expr, LoadName): 427 self.namespace.revoke(expr.name, attr) 428 elif isinstance(expr, LoadAttr): 429 for expr_attr in expr.expr.types: 430 if hasattr(expr_attr.type, "namespace"): 431 expr_attr.type.namespace.revoke(expr.name, attr) 432 elif isinstance(expr, LoadExc): 433 self.namespace.revoke_exception_type(attr) 434 435 def visitLoadExc(self, loadexc): 436 self.namespace.types = self.namespace.raises[:] 437 self.annotate(loadexc) 438 return loadexc 439 440 def visitLoadName(self, loadname): 441 self.namespace.set_types(self.namespace.load(loadname.name)) 442 result = loadname 443 self.annotate(result) 444 return result 445 446 def visitLoadRef(self, loadref): 447 self.namespace.set_types([Attribute(None, loadref.ref)]) 448 self.annotate(loadref) 449 return loadref 450 451 def visitLoadTemp(self, loadtemp): 452 index = getattr(loadtemp, "index", None) 453 try: 454 if getattr(loadtemp, "release", 0): 455 self.namespace.set_types(self.namespace.temp[index].pop()) 456 else: 457 self.namespace.set_types(self.namespace.temp[index][-1]) 458 except KeyError: 459 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 460 self.annotate(loadtemp) 461 return loadtemp 462 463 def visitNot(self, not_): 464 not_.expr = self.dispatch(not_.expr) 465 return not_ 466 467 def visitRaise(self, raise_): 468 if getattr(raise_, "traceback", None) is not None: 469 raise_.traceback = self.dispatch(raise_.traceback) 470 raise_.expr = self.dispatch(raise_.expr) 471 472 # Handle bare name exceptions by converting any classes to instances. 473 474 if not isinstance(raise_.expr, InvokeFunction): 475 raise_.pos_args = [] 476 raise_.kw_args = {} 477 raise_.star = None 478 raise_.dstar = None 479 types = [] 480 for attr in self.namespace.types: 481 if isinstance(attr.type, Class): 482 self._visitInvoke(raise_, [attr], have_args=0) 483 types += self.namespace.types 484 else: 485 types = self.namespace.types 486 487 combine(self.namespace.raises, types) 488 return raise_ 489 490 def visitReleaseTemp(self, releasetemp): 491 index = getattr(releasetemp, "index", None) 492 try: 493 self.namespace.temp[index].pop() 494 except KeyError: 495 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 496 except IndexError: 497 pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index 498 return releasetemp 499 500 def visitReturn(self, return_): 501 if hasattr(return_, "expr"): 502 return_.expr = self.dispatch(return_.expr) 503 combine(self.namespace.returns, self.namespace.types) 504 self.annotate(return_) 505 self.namespace.snapshot() 506 return return_ 507 508 visitReturnFromBlock = visitReturn 509 visitReturnFromFunction = visitReturn 510 511 def visitStoreAttr(self, storeattr): 512 storeattr.expr = self.dispatch(storeattr.expr) 513 expr = self.namespace.types 514 storeattr.lvalue = self.dispatch(storeattr.lvalue) 515 writes = {} 516 non_writes = [] 517 for attr in self.namespace.types: 518 if attr is None: 519 if not attr in non_writes: 520 non_writes.append(attr) 521 continue 522 attr.type.namespace.add(storeattr.name, expr) 523 writes[attr.type] = attr.type.namespace.load(storeattr.name) 524 if not writes: 525 print "Unable to store attribute", storeattr.name, "given", self.namespace.types 526 storeattr.writes = writes 527 storeattr.non_writes = non_writes 528 return storeattr 529 530 def visitStoreName(self, storename): 531 storename.expr = self.dispatch(storename.expr) 532 self.namespace.store(storename.name, self.namespace.types) 533 return storename 534 535 def visitStoreTemp(self, storetemp): 536 storetemp.expr = self.dispatch(storetemp.expr) 537 index = getattr(storetemp, "index", None) 538 if not self.namespace.temp.has_key(index): 539 self.namespace.temp[index] = [] 540 self.namespace.temp[index].append(self.namespace.types) 541 return storetemp 542 543 # Invocations are a chapter of their own. 544 545 def visitInvokeBlock(self, invoke): 546 547 # First find the callables. 548 549 invoke.expr = self.dispatch(invoke.expr) 550 invocation_types = self.namespace.types 551 return self._visitInvoke(invoke, invocation_types, have_args=0) 552 553 def visitInvokeFunction(self, invoke): 554 555 # First find the callables. 556 557 invoke.expr = self.dispatch(invoke.expr) 558 invocation_types = self.namespace.types 559 560 # Invocation processing starts with making sure that the arguments have 561 # been processed. 562 563 return self._visitInvoke(invoke, invocation_types, have_args=self.process_args(invoke)) 564 565 def _visitInvoke(self, invoke, invocation_types, have_args): 566 567 # Now locate and invoke the subprogram. This can be complicated because 568 # the target may be a class or object, and there may be many different 569 # related subprograms. 570 571 invocations = [] 572 573 # Visit each callable in turn, finding subprograms. 574 575 for attr in invocation_types: 576 577 # Deal with class invocations by providing instance objects. 578 # Here, each class is queried for the __init__ method, which may 579 # exist for some combinations of classes in a hierarchy but not for 580 # others. 581 582 if isinstance(attr.type, Class): 583 attributes = get_attributes(attr.type, "__init__") 584 585 # Deal with object invocations by using __call__ methods. 586 587 elif isinstance(attr.type, Instance): 588 attributes = get_attributes(attr.type, "__call__") 589 590 # Normal functions or methods are more straightforward. 591 # Here, we model them using an attribute with no context and with 592 # no associated accessor. 593 594 else: 595 attributes = [(attr, None)] 596 597 # Inspect each attribute and extract the subprogram. 598 599 for attribute, accessor in attributes: 600 601 # If a class is involved, presume that it must create a new 602 # object. 603 604 if isinstance(attr.type, Class): 605 606 # Instantiate the class. 607 # NOTE: Should probably only allocate a single instance. 608 609 instance = self.new_instance(invoke, "new", attr.type.full_name(), attr.type) 610 611 # For instantiations, switch the context. 612 613 if attribute is not None: 614 attribute = Attribute(instance, attribute.type) 615 616 # Skip cases where no callable is found. 617 618 if attribute is not None: 619 620 # If a subprogram is defined, invoke it. 621 622 self.invoke_subprogram(invoke, attribute) 623 if attribute.type not in invocations: 624 invocations.append(attribute.type) 625 626 elif not isinstance(attr.type, Class): 627 print "Invocation type is None for", accessor 628 629 else: 630 631 # Test to see if no arguments were supplied in cases where no 632 # initialiser was found. 633 634 if have_args: 635 raise AnnotationMessage, "No initialiser found for '%s' with arguments." % attr.type 636 637 # Special case: initialisation. 638 639 if isinstance(attr.type, Class): 640 641 # Associate the instance with the result of this invocation. 642 643 self.namespace.set_types([Attribute(None, instance)]) 644 self.annotate(invoke) 645 646 # Remember the invocations that were found, along with the return type 647 # information. 648 649 invoke.invocations = invocations 650 self.namespace.set_types(getattr(invoke, "types", [])) 651 return invoke 652 653 # Utility methods. 654 655 def new_instance(self, node, reason, target, type): 656 657 "Create, on the given 'node', a new instance with the given 'type'." 658 659 if not hasattr(node, "instances"): 660 node.instances = {} 661 662 if not node.instances.has_key((reason, target, type)): 663 664 # Insist on a single instance per type. 665 # NOTE: Strategy-dependent instantiation. 666 667 if len(type.instances) == 0: 668 instance = Instance() 669 instance.namespace = Namespace() 670 instance.namespace.store("__class__", [Attribute(None, type)]) 671 type.instances.append(instance) 672 else: 673 instance = type.instances[0] 674 675 node.instances[(reason, target, type)] = instance 676 677 return node.instances[(reason, target, type)] 678 679 def invoke_subprogram(self, invoke, subprogram): 680 681 "Invoke using the given 'invoke' node the given 'subprogram'." 682 683 # Test for context information, making it into a real attribute. 684 685 if subprogram.context is not None: 686 context = Attribute(None, subprogram.context) 687 target = subprogram.type 688 else: 689 context = None 690 target = subprogram.type 691 692 # Provide the correct namespace for the invocation. 693 694 if getattr(invoke, "share_locals", 0): 695 namespace = Namespace() 696 namespace.merge_namespace(self.namespace, everything=0) 697 using_module_namespace = self.namespace is self.module.namespace 698 elif getattr(target, "structure", None): 699 namespace = Namespace() 700 using_module_namespace = 0 701 else: 702 items = self.make_items(invoke, target, context) 703 namespace = self.make_namespace(items) 704 using_module_namespace = 0 705 706 # Test to see if anything has changed. 707 708 if hasattr(invoke, "syscount") and invoke.syscount == self.system.count: 709 return 710 711 # Remember the state of the system. 712 713 else: 714 invoke.syscount = self.system.count 715 716 # Process the subprogram. 717 # In order to keep global accesses working, the module namespace must be 718 # adjusted. 719 720 if using_module_namespace: 721 self.module.namespace = namespace 722 723 self.process_node(target, namespace) 724 725 # NOTE: Improve and verify this. 726 # If the invocation returns a value, acquire the return types. 727 728 if getattr(target, "returns_value", 0): 729 self.namespace.set_types(self.last_returns) 730 self.annotate(invoke) 731 732 # If it is a normal block, merge the locals. 733 # This can happen in addition to the above because for things like 734 # logical expressions, the namespace can be modified whilst values are 735 # returned as results. 736 737 if getattr(invoke, "share_locals", 0): 738 self.namespace.reset() 739 740 # Merge the locals snapshots. 741 742 for locals in self.returned_locals: 743 744 # For blocks returning values (such as operations), do not merge 745 # snapshots or results. 746 747 if getattr(target, "returns_value", 0): 748 self.namespace.merge_namespace(locals, everything=0) 749 750 # For blocks not returning values (such as loops), merge 751 # snapshots and results since they contain details of genuine 752 # returns. 753 754 else: 755 self.namespace.merge_namespace(locals) 756 757 # Incorporate any raised exceptions. 758 759 combine(self.namespace.raises, self.last_raises) 760 761 # In order to keep global accesses working, the module namespace must be 762 # adjusted. 763 764 if using_module_namespace: 765 self.module.namespace = self.namespace 766 767 def process_args(self, invocation): 768 769 """ 770 Process the arguments associated with an 'invocation'. Return whether 771 any arguments were processed. 772 """ 773 774 invocation.pos_args = self.dispatches(invocation.pos_args) 775 invocation.kw_args = self.dispatch_dict(invocation.kw_args) 776 777 # Get type information for star and dstar arguments. 778 779 if invocation.star is not None: 780 param, default = invocation.star 781 default = self.dispatch(default) 782 invocation.star = param, default 783 784 if invocation.dstar is not None: 785 param, default = invocation.dstar 786 default = self.dispatch(default) 787 invocation.dstar = param, default 788 789 if invocation.pos_args or invocation.kw_args or invocation.star or invocation.dstar: 790 return 1 791 else: 792 return 0 793 794 def make_items(self, invocation, subprogram, context): 795 796 """ 797 Make an items mapping for the 'invocation' of the 'subprogram' using the 798 given 'context' (which may be None). 799 """ 800 801 if context is not None: 802 pos_args = [Self(context)] + invocation.pos_args 803 else: 804 pos_args = invocation.pos_args 805 kw_args = invocation.kw_args 806 807 # Sort the arguments into positional and keyword arguments. 808 809 params = subprogram.params 810 items = [] 811 star_args = [] 812 813 # Match each positional argument, taking excess arguments as star args. 814 815 for arg in pos_args: 816 if params: 817 param, default = params[0] 818 if arg is None: 819 arg = default 820 if hasattr(arg, "types"): 821 items.append((param, arg.types)) 822 else: 823 items.append((param, [])) # Annotation has not succeeded. 824 params = params[1:] 825 else: 826 star_args.append(arg) 827 828 # Collect the remaining defaults. 829 830 while params: 831 param, default = params[0] 832 if kw_args.has_key(param): 833 arg = kw_args[param] 834 del kw_args[param] 835 elif default is not None: 836 arg = self.dispatch(default) 837 else: 838 raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param) 839 if hasattr(arg, "types"): 840 items.append((param, arg.types)) 841 else: 842 items.append((param, [])) # Annotation has not succeeded. 843 params = params[1:] 844 845 dstar_args = kw_args.values() 846 847 # Construct temporary objects. 848 849 if star_args: 850 star_invocation = self.make_star_args(invocation, subprogram, star_args) 851 self.dispatch(star_invocation) 852 star_types = star_invocation.types 853 else: 854 star_types = None 855 856 if dstar_args: 857 dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args) # NOTE: To be written! 858 self.dispatch(dstar_invocation) 859 dstar_types = dstar_invocation.types 860 else: 861 dstar_types = None 862 863 # NOTE: Merge the objects properly. 864 865 star_types = star_types or invocation.star and invocation.star.types 866 dstar_types = dstar_types or invocation.dstar and invocation.dstar.types 867 868 # Add star and dstar. 869 870 if star_types is not None: 871 if subprogram.star is not None: 872 param, default = subprogram.star 873 items.append((param, star_types)) 874 else: 875 raise AnnotationMessage, "Invocation provides unwanted *args." 876 elif subprogram.star is not None: 877 param, default = subprogram.star 878 if not hasattr(arg, "types"): 879 arg = self.dispatch(default) # NOTE: Review reprocessing. 880 items.append((param, arg.types)) 881 882 if dstar_types is not None: 883 if subprogram.dstar is not None: 884 param, default = subprogram.dstar 885 items.append((param, dstar_types)) 886 else: 887 raise AnnotationMessage, "Invocation provides unwanted **args." 888 elif subprogram.dstar is not None: 889 param, default = subprogram.dstar 890 if not hasattr(arg, "types"): 891 arg = self.dispatch(default) # NOTE: Review reprocessing. 892 items.append((param, arg.types)) 893 894 # Record the parameter types. 895 896 self.annotate_parameters(subprogram, items) 897 return subprogram.paramtypes.items() 898 899 def make_star_args(self, invocation, subprogram, star_args): 900 901 "Make a subprogram which initialises a list containing 'star_args'." 902 903 if not hasattr(invocation, "stars"): 904 invocation.stars = {} 905 906 if not invocation.stars.has_key(subprogram.full_name()): 907 code=[ 908 StoreTemp( 909 expr=InvokeFunction( 910 expr=LoadAttr( 911 expr=LoadRef( 912 ref=self.builtins 913 ), 914 name="list", 915 nstype="module", 916 ), 917 args=[], 918 star=None, 919 dstar=None 920 ) 921 ) 922 ] 923 924 for arg in star_args: 925 code.append( 926 InvokeFunction( 927 expr=LoadAttr( 928 expr=LoadTemp(), 929 name="append" 930 ), 931 args=[arg], 932 star=None, 933 dstar=None 934 ) 935 ) 936 937 code += [ 938 Return(expr=LoadTemp(release=1)) 939 ] 940 941 invocation.stars[subprogram.full_name()] = InvokeBlock( 942 produces_result=1, 943 expr=LoadRef( 944 ref=Subprogram( 945 name=None, 946 returns_value=1, 947 params=[], 948 star=None, 949 dstar=None, 950 code=code 951 ) 952 ) 953 ) 954 955 return invocation.stars[subprogram.full_name()] 956 957 def make_namespace(self, items): 958 namespace = Namespace() 959 namespace.merge_items(items) 960 return namespace 961 962 # Namespace-related abstractions. 963 964 class Namespace: 965 966 """ 967 A local namespace which may either relate to a genuine set of function 968 locals or the initialisation of a structure or module. 969 """ 970 971 def __init__(self): 972 973 """ 974 Initialise the namespace with a mapping of local names to possible 975 types, a list of return values and of possible returned local 976 namespaces. The namespace also tracks the "current" types and a mapping 977 of temporary value names to types. 978 """ 979 980 self.names = {} 981 self.returns = [] 982 self.return_locals = [] 983 self.raises = [] 984 self.temp = {} 985 self.types = [] 986 987 def set_types(self, types): 988 self.types = types 989 990 def add(self, name, types): 991 if self.names.has_key(name): 992 combine(self.names[name], types) 993 else: 994 self.store(name, types) 995 996 def store(self, name, types): 997 self.names[name] = types 998 999 __setitem__ = store 1000 1001 def load(self, name): 1002 return self.names[name] 1003 1004 __getitem__ = load 1005 1006 def revoke(self, name, type): 1007 self.names[name].remove(type) 1008 1009 def revoke_exception_type(self, type): 1010 self.raises.remove(type) 1011 1012 def merge_namespace(self, namespace, everything=1): 1013 self.merge_items(namespace.names.items()) 1014 if everything: 1015 combine(self.returns, namespace.returns) 1016 combine(self.return_locals, namespace.return_locals) 1017 combine(self.raises, namespace.raises) 1018 for name, values in namespace.temp.items(): 1019 if values: 1020 if not self.temp.has_key(name) or not self.temp[name]: 1021 self.temp[name] = [[]] 1022 combine(self.temp[name][-1], values[-1]) 1023 1024 def merge_items(self, items): 1025 for name, types in items: 1026 self.merge(name, types) 1027 1028 def merge(self, name, types): 1029 if not self.names.has_key(name): 1030 self.names[name] = types[:] 1031 else: 1032 existing = self.names[name] 1033 combine(existing, types) 1034 1035 def snapshot(self): 1036 1037 "Make a snapshot of the locals and remember them." 1038 1039 namespace = Namespace() 1040 namespace.merge_namespace(self) 1041 self.return_locals.append(namespace) 1042 1043 def reset(self): 1044 1045 "Reset a namespace in preparation for merging with returned locals." 1046 1047 self.names = {} 1048 1049 def __repr__(self): 1050 return repr(self.names) 1051 1052 class Attribute: 1053 1054 """ 1055 An attribute abstraction, indicating the type of the attribute along with 1056 its context or origin. 1057 """ 1058 1059 def __init__(self, context, type): 1060 self.context = context 1061 self.type = type 1062 1063 def __eq__(self, other): 1064 return hasattr(other, "type") and other.type == self.type or other == self.type 1065 1066 def __repr__(self): 1067 return "Attribute(%s, %s)" % (repr(self.context), repr(self.type)) 1068 1069 class Self: 1070 1071 """ 1072 A program node encapsulating object/context information in an argument list. 1073 This is not particularly like Attribute, Class, Instance or other such 1074 things, since it actually appears in the program representation. 1075 """ 1076 1077 def __init__(self, attribute): 1078 self.types = [attribute] 1079 1080 def combine(target, additions): 1081 1082 """ 1083 Merge into the 'target' sequence the given 'additions', preventing duplicate 1084 items. 1085 """ 1086 1087 for addition in additions: 1088 if addition not in target: 1089 target.append(addition) 1090 1091 def find_attributes(structure, name): 1092 1093 """ 1094 Find for the given 'structure' all attributes for the given 'name', visiting 1095 base classes where appropriate and returning the attributes in order of 1096 descending precedence for all possible base classes. 1097 1098 The elements in the result list are 2-tuples which contain the attribute and 1099 the structure involved in accessing the attribute. 1100 """ 1101 1102 # First attempt to search the instance/class namespace. 1103 1104 try: 1105 l = structure.namespace.load(name) 1106 attributes = [] 1107 for attribute in l: 1108 attributes.append((attribute, structure)) 1109 1110 # If that does not work, attempt to investigate any class or base classes. 1111 1112 except KeyError: 1113 attributes = [] 1114 1115 # Investigate any instance's implementing class. 1116 1117 if isinstance(structure, Instance): 1118 for attr in structure.namespace.load("__class__"): 1119 cls = attr.type 1120 l = get_attributes(cls, name) 1121 combine(attributes, l) 1122 1123 # Investigate any class's base classes. 1124 1125 elif isinstance(structure, Class): 1126 1127 # If no base classes exist, return an indicator that no attribute 1128 # exists. 1129 1130 if not structure.base_refs: 1131 return [(None, structure)] 1132 1133 # Otherwise, find all possible base classes. 1134 1135 for base_refs in structure.base_refs: 1136 base_attributes = [] 1137 1138 # For each base class, find attributes either in the base 1139 # class or its own base classes. 1140 1141 for base_ref in base_refs: 1142 l = get_attributes(base_ref, name) 1143 combine(base_attributes, l) 1144 1145 combine(attributes, base_attributes) 1146 1147 return attributes 1148 1149 def get_attributes(structure, name): 1150 1151 """ 1152 Return all possible attributes for the given 'structure' having the given 1153 'name', wrapping each attribute in an Attribute object which includes 1154 context information for the attribute access. 1155 1156 The elements in the result list are 2-tuples which contain the attribute and 1157 the structure involved in accessing the attribute. 1158 """ 1159 1160 if isinstance(structure, Attribute): 1161 structure = structure.type 1162 results = [] 1163 for attribute, accessor in find_attributes(structure, name): 1164 if attribute is not None and isinstance(structure, Structure): 1165 results.append((Attribute(structure, attribute.type), accessor)) 1166 else: 1167 results.append((attribute, accessor)) 1168 return results 1169 1170 # Convenience functions. 1171 1172 def annotate(module, builtins=None): 1173 1174 """ 1175 Annotate the given 'module', also employing the optional 'builtins' module, 1176 if specified. 1177 """ 1178 1179 annotator = Annotator() 1180 if builtins is not None: 1181 annotator.process(module, builtins) 1182 else: 1183 annotator.process(module) 1184 1185 def annotate_all(modules, builtins): 1186 annotate(builtins) 1187 for module in modules: 1188 annotate(module, builtins) 1189 1190 # vim: tabstop=4 expandtab shiftwidth=4