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 def init(self, node): 59 if not hasattr(node, "types"): 60 node.types = [] 61 def annotate(self, node, types): 62 self.init(node) 63 for type in types: 64 if type not in node.types: 65 node.types.append(type) 66 self.count += 1 67 68 system = System() 69 70 # Exceptions. 71 72 class AnnotationError(SimplifiedError): 73 74 "An error in the annotation process." 75 76 pass 77 78 class AnnotationMessage(Exception): 79 80 "A lesser annotation error." 81 82 pass 83 84 # Annotation. 85 86 class Annotator(Visitor): 87 88 """ 89 The type annotator which traverses the program nodes, typically depth-first, 90 and maintains a record of the current set of types applying to the currently 91 considered operation. Such types are also recorded on the nodes, and a 92 special "system" record is maintained to monitor the level of annotation 93 activity with a view to recognising when no more annotations are possible. 94 95 Throughout the annotation activity, type information consists of lists of 96 Attribute objects where such objects retain information about the context of 97 the type (since a value in the program may be associated with an object or 98 class) and the actual type of the value being manipulated. Upon accessing 99 attribute information on namespaces, additional accessor information is also 100 exchanged - this provides a means of distinguishing between the different 101 types possible when the means of constructing the namespace may depend on 102 run-time behaviour. 103 """ 104 105 def __init__(self): 106 107 "Initialise the visitor." 108 109 Visitor.__init__(self) 110 self.system = system 111 112 # Satisfy visitor issues. 113 114 self.visitor = self 115 116 def process(self, module, builtins=None): 117 118 """ 119 Process the given 'module', using the optional 'builtins' to access 120 built-in classes and functions. 121 """ 122 123 self.subprograms = [] 124 self.current_subprograms = [] 125 self.current_namespaces = [] 126 127 # Give constants their own namespace. 128 129 for value, constant in module.simplifier.constants.items(): 130 constant.namespace = Namespace() 131 132 # Process the module, supplying builtins if possible. 133 134 self.builtins = builtins 135 self.global_namespace = Namespace() 136 137 if builtins is not None: 138 self.builtins_namespace = builtins.namespace 139 else: 140 self.builtins_namespace = self.global_namespace 141 142 return self.process_node(module) 143 144 def process_node(self, node, locals=None): 145 146 """ 147 Process a subprogram or module 'node', indicating any initial 'locals'. 148 Return an annotated subprogram or module. Note that this method may 149 mutate nodes in the original program. 150 """ 151 152 # Determine the namespace. 153 154 if locals is not None: 155 self.namespace = locals 156 else: 157 self.namespace = self.global_namespace 158 159 # Record the current subprogram and namespace. 160 161 self.current_subprograms.append(node) 162 self.current_namespaces.append(self.namespace) 163 164 # Add namespace details to any structure involved. 165 166 if getattr(node, "structure", None) is not None: 167 node.structure.namespace = Namespace() 168 169 # Initialise bases where appropriate. 170 171 if hasattr(node.structure, "bases"): 172 base_refs = [] 173 for base in node.structure.bases: 174 self.dispatch(base) 175 base_refs.append(self.namespace.types) 176 node.structure.base_refs = base_refs 177 178 # Dispatch to the code itself. 179 180 node.namespace = self.namespace 181 result = self.dispatch(node) 182 result.namespace = self.namespace 183 184 # Obtain the return values. 185 186 self.last_returns = self.namespace.returns 187 self.returned_locals = self.namespace.return_locals 188 189 # Restore the previous subprogram and namespace. 190 191 self.current_namespaces.pop() 192 if self.current_namespaces: 193 self.namespace = self.current_namespaces[-1] 194 195 self.current_subprograms.pop() 196 197 return result 198 199 def annotate(self, node, types=None): 200 201 """ 202 Annotate the given 'node' in the system, using either the optional 203 'types' or the namespace's current type information. 204 """ 205 206 self.system.annotate(node, types or self.namespace.types) 207 208 # Visitor methods. 209 210 def default(self, node): 211 212 """ 213 Process the given 'node', given that it does not have a specific 214 handler. 215 """ 216 217 for attr in ("expr", "lvalue", "test", "handler"): 218 value = getattr(node, attr, None) 219 if value is not None: 220 setattr(node, attr, self.dispatch(value)) 221 for attr in ("body", "else_", "finally_", "code"): 222 value = getattr(node, attr, None) 223 if value is not None: 224 setattr(node, attr, self.dispatches(value)) 225 return node 226 227 def dispatch(self, node, *args): 228 try: 229 return Visitor.dispatch(self, node, *args) 230 except AnnotationError, exc: 231 exc.add(node) 232 raise 233 except AnnotationMessage, exc: 234 raise AnnotationError(exc, node) 235 236 def visitLoadRef(self, loadref): 237 self.namespace.set_types([Attribute(None, loadref.ref)]) 238 self.annotate(loadref) 239 return loadref 240 241 def visitLoadName(self, loadname): 242 self.namespace.set_types(self.namespace.load(loadname.name)) 243 result = loadname 244 self.annotate(result) 245 return result 246 247 def visitStoreName(self, storename): 248 storename.expr = self.dispatch(storename.expr) 249 self.namespace.store(storename.name, self.namespace.types) 250 return storename 251 252 def visitLoadTemp(self, loadtemp): 253 index = getattr(loadtemp, "index", None) 254 try: 255 if getattr(loadtemp, "release", 0): 256 self.namespace.set_types(self.namespace.temp[index].pop()) 257 else: 258 self.namespace.set_types(self.namespace.temp[index][-1]) 259 except KeyError: 260 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 261 self.annotate(loadtemp) 262 return loadtemp 263 264 def visitStoreTemp(self, storetemp): 265 storetemp.expr = self.dispatch(storetemp.expr) 266 index = getattr(storetemp, "index", None) 267 if not self.namespace.temp.has_key(index): 268 self.namespace.temp[index] = [] 269 self.namespace.temp[index].append(self.namespace.types) 270 return storetemp 271 272 def visitReleaseTemp(self, releasetemp): 273 index = getattr(releasetemp, "index", None) 274 try: 275 self.namespace.temp[index].pop() 276 except KeyError: 277 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 278 except IndexError: 279 pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index 280 return releasetemp 281 282 def visitLoadAttr(self, loadattr): 283 loadattr.expr = self.dispatch(loadattr.expr) 284 types = [] 285 accesses = {} 286 non_accesses = {} 287 for attr in self.namespace.types: 288 for attribute, accessor in get_attributes(attr.type, loadattr.name): 289 if attribute is not None: 290 types.append(attribute) 291 if not accesses.has_key(attr.type): 292 accesses[attr.type] = [] 293 if not (attribute, accessor) in accesses[attr.type]: 294 accesses[attr.type].append((attribute, accessor)) 295 else: 296 print "Empty attribute", loadattr.name, "via accessor", accessor 297 if not non_accesses.has_key(attr.type): 298 non_accesses[attr.type] = [] 299 if not (attribute, accessor) in non_accesses[attr.type]: 300 non_accesses[attr.type].append((attribute, accessor)) 301 self.namespace.set_types(types) 302 loadattr.accesses = accesses 303 loadattr.non_accesses = non_accesses 304 self.annotate(loadattr) 305 return loadattr 306 307 def visitStoreAttr(self, storeattr): 308 storeattr.expr = self.dispatch(storeattr.expr) 309 expr = self.namespace.types 310 storeattr.lvalue = self.dispatch(storeattr.lvalue) 311 writes = {} 312 for attr in self.namespace.types: 313 if attr is None: 314 print "Empty attribute storage attempt" 315 continue 316 attr.type.namespace.store(storeattr.name, expr) 317 writes[attr.type] = attr.type.namespace.load(storeattr.name) 318 storeattr.writes = writes 319 return storeattr 320 321 def visitConditional(self, conditional): 322 323 # Conditionals keep local namespace changes isolated. 324 # With Return nodes inside the body/else sections, the changes are 325 # communicated to the caller. 326 327 conditional.test = self.dispatch(conditional.test) 328 saved_namespace = self.namespace 329 330 self.namespace = Namespace() 331 self.namespace.merge_namespace(saved_namespace) 332 conditional.body = self.dispatches(conditional.body) 333 body_namespace = self.namespace 334 335 self.namespace = Namespace() 336 self.namespace.merge_namespace(saved_namespace) 337 conditional.else_ = self.dispatches(conditional.else_) 338 else_namespace = self.namespace 339 340 self.namespace = Namespace() 341 self.namespace.merge_namespace(body_namespace) 342 self.namespace.merge_namespace(else_namespace) 343 return conditional 344 345 def visitReturn(self, return_): 346 if hasattr(return_, "expr"): 347 return_.expr = self.dispatch(return_.expr) 348 combine(self.namespace.returns, self.namespace.types) 349 self.annotate(return_) 350 self.namespace.snapshot() 351 return return_ 352 353 def visitInvoke(self, invoke): 354 355 # First find the callables. 356 357 invoke.expr = self.dispatch(invoke.expr) 358 invocation_types = self.namespace.types 359 360 # Invocation processing starts with making sure that the arguments have 361 # been processed. 362 363 if isinstance(invoke, InvokeFunction): 364 self.process_args(invoke) 365 366 # Now locate and invoke the subprogram. This can be complicated because 367 # the target may be a class or object, and there may be many different 368 # related subprograms. 369 370 invocations = [] 371 372 # Visit each callable in turn, finding subprograms. 373 374 for attr in invocation_types: 375 376 # Deal with class invocations by providing instance objects. 377 # Here, each class is queried for the __init__ method, which may 378 # exist for some combinations of classes in a hierarchy but not for 379 # others. 380 381 if isinstance(attr.type, Class): 382 attributes = get_attributes(attr.type, "__init__") 383 384 # Deal with object invocations by using __call__ methods. 385 386 elif isinstance(attr.type, Instance): 387 attributes = get_attributes(attr.type, "__call__") 388 389 # Normal functions or methods are more straightforward. 390 # Here, we model them using an attribute with no context and with 391 # no associated accessor. 392 393 else: 394 attributes = [(attr, None)] 395 396 # Inspect each attribute and extract the subprogram. 397 398 for attribute, accessor in attributes: 399 400 # If a class is involved, presume that it must create a new 401 # object. 402 403 if isinstance(attr.type, Class): 404 405 # Instantiate the class. 406 # NOTE: Should probably only allocate a single instance. 407 408 instance = self.new_instance(invoke, "new", attr.type.full_name(), attr.type) 409 410 # For instantiations, switch the context. 411 412 if attribute is not None: 413 attribute = Attribute(instance, attribute.type) 414 415 # Skip cases where no callable is found. 416 417 if attribute is not None: 418 419 # If a subprogram is defined, invoke it. 420 421 self.invoke_subprogram(invoke, attribute) 422 if attribute.type not in invocations: 423 invocations.append(attribute.type) 424 425 elif not isinstance(attr.type, Class): 426 print "Invocation type is None for", accessor 427 428 # Special case: initialisation. 429 430 if isinstance(attr.type, Class): 431 432 # Associate the instance with the result of this invocation. 433 434 self.namespace.set_types([Attribute(None, instance)]) 435 self.annotate(invoke) 436 437 # Remember the invocations that were found, along with the return type 438 # information. 439 440 invoke.invocations = invocations 441 self.namespace.set_types(getattr(invoke, "types", [])) 442 return invoke 443 444 visitInvokeFunction = visitInvoke 445 visitInvokeBlock = visitInvoke 446 447 # Utility methods. 448 449 def new_instance(self, node, reason, target, type): 450 451 "Create, on the given 'node', a new instance with the given 'type'." 452 453 if not hasattr(node, "instances"): 454 node.instances = {} 455 456 if not node.instances.has_key((reason, target, type)): 457 instance = Instance() 458 instance.namespace = Namespace() 459 instance.namespace.store("__class__", [Attribute(None, type)]) 460 node.instances[(reason, target, type)] = instance 461 462 return node.instances[(reason, target, type)] 463 464 def invoke_subprogram(self, invoke, subprogram): 465 466 "Invoke using the given 'invoke' node the given 'subprogram'." 467 468 # Test to see if anything has changed. 469 470 if hasattr(invoke, "syscount") and invoke.syscount == self.system.count: 471 return 472 473 # Remember the state of the system. 474 475 else: 476 invoke.syscount = self.system.count 477 478 # Test for context information, making it into a real attribute. 479 480 if subprogram.context is not None: 481 context = Attribute(None, subprogram.context) 482 target = subprogram.type 483 else: 484 context = None 485 target = subprogram.type 486 487 # Provide the correct namespace for the invocation. 488 489 if isinstance(invoke, InvokeBlock): 490 namespace = Namespace() 491 namespace.merge_namespace(self.namespace) 492 else: 493 items = self.make_items(invoke, target, context) 494 namespace = self.make_namespace(items) 495 496 # Process the subprogram. 497 498 self.process_node(target, namespace) 499 500 # NOTE: Improve and verify this. 501 502 if getattr(target, "returns_value", 0): 503 self.namespace.set_types(self.last_returns) 504 self.annotate(invoke) 505 506 if isinstance(invoke, InvokeBlock): 507 for locals in self.returned_locals: 508 self.namespace.merge_namespace(locals) 509 510 def process_args(self, invocation): 511 512 "Process the arguments associated with an 'invocation'." 513 514 # NOTE: Consider initialiser invocation for classes. 515 516 types = [] 517 args = [] 518 519 # Get type information for regular arguments. 520 521 for arg in invocation.args: 522 args.append(self.dispatch(arg)) 523 types.append(self.namespace.types) 524 525 # Get type information for star and dstar arguments. 526 527 if invocation.star is not None: 528 param, default = invocation.star 529 default = self.dispatch(default) 530 invocation.star = param, default 531 types.append(default.types) 532 533 if invocation.dstar is not None: 534 param, default = invocation.dstar 535 default = self.dispatch(default) 536 invocation.dstar = param, default 537 types.append(default.types) 538 539 invocation.args = args 540 541 def make_items(self, invocation, subprogram, context): 542 543 """ 544 Make an items mapping for the 'invocation' of the 'subprogram' using the 545 given 'context' (which may be None). 546 """ 547 548 if context is not None: 549 args = [Self(context)] + invocation.args 550 else: 551 args = invocation.args 552 553 # Sort the arguments into positional and keyword arguments. 554 555 pos_args = [] 556 kw_args = [] 557 add_kw = 0 558 for arg in args: 559 if not add_kw: 560 if not isinstance(arg, Keyword): 561 pos_args.append(arg) 562 else: 563 add_kw = 1 564 if add_kw: 565 if isinstance(arg, Keyword): 566 kw_args.append(arg) 567 else: 568 raise AnnotationMessage, "Positional argument appears after keyword arguments in '%s'." % callfunc 569 570 params = subprogram.params 571 items = [] 572 star_args = [] 573 574 # Match each positional argument, taking excess arguments as star args. 575 576 for arg in pos_args: 577 if params: 578 param, default = params[0] 579 if arg is None: 580 arg = default 581 items.append((param, arg.types)) 582 params = params[1:] 583 else: 584 star_args.append(arg) 585 586 # Collect the remaining defaults. 587 588 while params: 589 param, default = params[0] 590 if kw_args.has_key(param): 591 arg = kw_args[param] 592 del kw_args[param] 593 elif default is None: 594 raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param) 595 items.append((param, arg.types)) 596 params = params[1:] 597 598 dstar_args = kw_args 599 600 # Construct temporary objects. 601 602 if star_args: 603 star_invocation = self.make_star_args(invocation, subprogram, star_args) 604 self.dispatch(star_invocation) 605 star_types = star_invocation.types 606 else: 607 star_types = None 608 609 if dstar_args: 610 dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args) # NOTE: To be written! 611 self.dispatch(dstar_invocation) 612 dstar_types = dstar_invocation.types 613 else: 614 dstar_types = None 615 616 # NOTE: Merge the objects properly. 617 618 star_types = star_types or invocation.star and invocation.star.types 619 dstar_types = dstar_types or invocation.dstar and invocation.dstar.types 620 621 # Add star and dstar. 622 623 if star_types is not None: 624 if subprogram.star is not None: 625 param, default = subprogram.star 626 items.append((param, star_types)) 627 else: 628 raise AnnotationMessage, "Invocation provides unwanted *args." 629 elif subprogram.star is not None: 630 param, default = subprogram.star 631 arg = self.dispatch(default) # NOTE: Review reprocessing. 632 items.append((param, arg.types)) 633 634 if dstar_types is not None: 635 if subprogram.dstar is not None: 636 param, default = subprogram.dstar 637 items.append((param, dstar_types)) 638 else: 639 raise AnnotationMessage, "Invocation provides unwanted **args." 640 elif subprogram.dstar is not None: 641 param, default = subprogram.dstar 642 arg = self.dispatch(default) # NOTE: Review reprocessing. 643 items.append((param, arg.types)) 644 645 # Record the parameter types. 646 647 subprogram.paramtypes = {} 648 for param, types in items: 649 subprogram.paramtypes[param] = types 650 651 return items 652 653 def make_star_args(self, invocation, subprogram, star_args): 654 655 "Make a subprogram which initialises a list containing 'star_args'." 656 657 if not hasattr(invocation, "stars"): 658 invocation.stars = {} 659 660 if not invocation.stars.has_key(subprogram.full_name()): 661 code=[ 662 StoreTemp( 663 expr=InvokeFunction( 664 expr=LoadAttr( 665 expr=LoadRef( 666 ref=self.builtins 667 ), 668 name="list", 669 nstype="module", 670 ), 671 args=[], 672 star=None, 673 dstar=None 674 ) 675 ) 676 ] 677 678 for arg in star_args: 679 code.append( 680 InvokeFunction( 681 expr=LoadAttr( 682 expr=LoadTemp(), 683 name="append" 684 ), 685 args=[arg], 686 star=None, 687 dstar=None 688 ) 689 ) 690 691 code += [ 692 Return(expr=LoadTemp(release=1)) 693 ] 694 695 invocation.stars[subprogram.full_name()] = InvokeBlock( 696 produces_result=1, 697 expr=LoadRef( 698 ref=Subprogram( 699 name=None, 700 returns_value=1, 701 params=[], 702 star=None, 703 dstar=None, 704 code=code 705 ) 706 ) 707 ) 708 709 return invocation.stars[subprogram.full_name()] 710 711 def make_namespace(self, items): 712 namespace = Namespace() 713 namespace.merge_items(items) 714 return namespace 715 716 # Namespace-related abstractions. 717 718 class Namespace: 719 720 """ 721 A local namespace which may either relate to a genuine set of function 722 locals or the initialisation of a structure or module. 723 """ 724 725 def __init__(self): 726 727 """ 728 Initialise the namespace with a mapping of local names to possible 729 types, a list of return values and of possible returned local 730 namespaces. The namespace also tracks the "current" types and a mapping 731 of temporary value names to types. 732 """ 733 734 self.names = {} 735 self.returns = [] 736 self.return_locals = [] 737 self.temp = {} 738 self.types = [] 739 740 def set_types(self, types): 741 self.types = types 742 743 def store(self, name, types): 744 self.names[name] = types 745 746 __setattr_ = store 747 748 def load(self, name): 749 return self.names[name] 750 751 __getattr__ = load 752 753 def merge_namespace(self, namespace): 754 self.merge_items(namespace.names.items()) 755 combine(self.returns, namespace.returns) 756 self.temp = namespace.temp 757 758 def merge_items(self, items): 759 for name, types in items: 760 self.merge(name, types) 761 762 def merge(self, name, types): 763 if not self.names.has_key(name): 764 self.names[name] = types[:] 765 else: 766 existing = self.names[name] 767 combine(existing, types) 768 769 def snapshot(self): 770 771 "Make a snapshot of the locals and remember them." 772 773 namespace = Namespace() 774 namespace.merge_namespace(self) 775 self.return_locals.append(namespace) 776 777 def __repr__(self): 778 return repr(self.names) 779 780 class Attribute: 781 782 """ 783 An attribute abstraction, indicating the type of the attribute along with 784 its context or origin. 785 """ 786 787 def __init__(self, context, type): 788 self.context = context 789 self.type = type 790 791 def __eq__(self, other): 792 return hasattr(other, "type") and other.type == self.type or other == self.type 793 794 def __repr__(self): 795 return "Attribute(%s, %s)" % (repr(self.context), repr(self.type)) 796 797 class Self: 798 def __init__(self, attribute): 799 self.types = [attribute] 800 801 def combine(target, additions): 802 for addition in additions: 803 if addition not in target: 804 target.append(addition) 805 806 def find_attributes(structure, name): 807 808 """ 809 Find for the given 'structure' all attributes for the given 'name', visiting 810 base classes where appropriate and returning the attributes in order of 811 descending precedence for all possible base classes. 812 813 The elements in the result list are 2-tuples which contain the attribute and 814 the structure involved in accessing the attribute. 815 """ 816 817 # First attempt to search the instance/class namespace. 818 819 try: 820 l = structure.namespace.load(name) 821 attributes = [] 822 for attribute in l: 823 attributes.append((attribute, structure)) 824 825 # If that does not work, attempt to investigate any class or base classes. 826 827 except KeyError: 828 attributes = [] 829 830 # Investigate any instance's implementing class. 831 832 if isinstance(structure, Instance): 833 for attr in structure.namespace.load("__class__"): 834 cls = attr.type 835 l = get_attributes(cls, name) 836 combine(attributes, l) 837 838 # Investigate any class's base classes. 839 840 elif isinstance(structure, Class): 841 842 # If no base classes exist, return an indicator that no attribute 843 # exists. 844 845 if not structure.base_refs: 846 return [(None, structure)] 847 848 # Otherwise, find all possible base classes. 849 850 for base_refs in structure.base_refs: 851 base_attributes = [] 852 853 # For each base class, find attributes either in the base 854 # class or its own base classes. 855 856 for base_ref in base_refs: 857 l = get_attributes(base_ref, name) 858 combine(base_attributes, l) 859 860 combine(attributes, base_attributes) 861 862 return attributes 863 864 def get_attributes(structure, name): 865 866 """ 867 Return all possible attributes for the given 'structure' having the given 868 'name', wrapping each attribute in an Attribute object which includes 869 context information for the attribute access. 870 871 The elements in the result list are 2-tuples which contain the attribute and 872 the structure involved in accessing the attribute. 873 """ 874 875 if isinstance(structure, Attribute): 876 structure = structure.type 877 results = [] 878 for attribute, accessor in find_attributes(structure, name): 879 if attribute is not None and isinstance(structure, Structure): 880 results.append((Attribute(structure, attribute.type), accessor)) 881 else: 882 results.append((attribute, accessor)) 883 return results 884 885 # Convenience functions. 886 887 def annotate(module, builtins=None): 888 889 """ 890 Annotate the given 'module', also employing the optional 'builtins' module, 891 if specified. 892 """ 893 894 annotator = Annotator() 895 if builtins is not None: 896 annotator.process(module, builtins) 897 else: 898 annotator.process(module) 899 900 def annotate_all(modules, builtins): 901 annotate(builtins) 902 for module in modules: 903 annotate(module, builtins) 904 905 # vim: tabstop=4 expandtab shiftwidth=4