1 #!/usr/bin/env python 2 3 """ 4 Inspect and obtain module structure. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 7 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk> 8 9 This program is free software; you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free Software 11 Foundation; either version 3 of the License, or (at your option) any later 12 version. 13 14 This program is distributed in the hope that it will be useful, but WITHOUT 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 17 details. 18 19 You should have received a copy of the GNU General Public License along with 20 this program. If not, see <http://www.gnu.org/licenses/>. 21 """ 22 23 from branching import BranchTracker 24 from common import get_argnames, init_item, predefined_constants 25 from modules import BasicModule, CacheWritingModule, InspectionNaming 26 from referencing import Reference 27 from resolving import NameResolving 28 from results import AccessRef, InstanceRef, InvocationRef, LiteralSequenceRef, \ 29 LocalNameRef, NameRef, ResolvedNameRef 30 import compiler 31 import sys 32 33 class InspectedModule(BasicModule, CacheWritingModule, NameResolving, InspectionNaming): 34 35 "A module inspector." 36 37 def __init__(self, name, importer): 38 39 "Initialise the module with basic details." 40 41 BasicModule.__init__(self, name, importer) 42 43 self.in_class = False 44 self.in_conditional = False 45 self.global_attr_accesses = {} 46 47 # Nested scope handling. 48 49 self.parent_function = None 50 self.propagated_names = {} 51 52 # Usage tracking. 53 54 self.trackers = [] 55 self.attr_accessor_branches = {} 56 57 def __repr__(self): 58 return "InspectedModule(%r, %r)" % (self.name, self.importer) 59 60 # Principal methods. 61 62 def parse(self, filename): 63 64 "Parse the file having the given 'filename'." 65 66 self.parse_file(filename) 67 68 # Inspect the module. 69 70 self.start_tracking_in_module() 71 72 # Detect and record imports and globals declared in the module. 73 74 self.assign_general_local("__name__", self.get_constant("str", self.name)) 75 self.assign_general_local("__file__", self.get_constant("str", filename)) 76 self.process_structure(self.astnode) 77 78 # Set the class of the module after the definition has occurred. 79 80 ref = self.get_builtin("object") 81 self.set_name("__class__", ref) 82 83 # Get module-level attribute usage details. 84 85 self.stop_tracking_in_module() 86 87 # Collect external name references. 88 89 self.collect_names() 90 91 def complete(self): 92 93 "Complete the module inspection." 94 95 # Resolve names not definitively mapped to objects. 96 97 self.resolve() 98 99 # Define the invocation requirements in each namespace. 100 101 self.set_invocation_usage() 102 103 # Propagate to the importer information needed in subsequent activities. 104 105 self.propagate() 106 107 # Accessory methods. 108 109 def collect_names(self): 110 111 "Collect the names used by each scope." 112 113 for path in self.names_used.keys(): 114 self.collect_names_for_path(path) 115 116 def collect_names_for_path(self, path): 117 118 """ 119 Collect the names used by the given 'path'. These are propagated to the 120 importer in advance of any dependency resolution. 121 """ 122 123 names = self.names_used.get(path) 124 if not names: 125 return 126 127 in_function = self.function_locals.has_key(path) 128 129 for name in names: 130 if name in predefined_constants or in_function and name in self.function_locals[path]: 131 continue 132 133 # Find local definitions (within dynamic namespaces). 134 135 key = "%s.%s" % (path, name) 136 ref = self.get_resolved_object(key) 137 if ref: 138 self.importer.all_name_references[key] = self.name_references[key] = ref 139 continue 140 141 # Find global or built-in definitions. 142 143 ref = self.get_resolved_global_or_builtin(name) 144 if ref: 145 self.importer.all_name_references[key] = self.name_references[key] = ref 146 continue 147 148 print >>sys.stderr, "Name not recognised: %s in %s" % (name, path) 149 init_item(self.names_missing, path, set) 150 self.names_missing[path].add(name) 151 152 def get_resolved_global_or_builtin(self, name): 153 154 "Return the resolved global or built-in object with the given 'name'." 155 156 return self.get_global(name) or self.importer.get_object("__builtins__.%s" % name) 157 158 # Module structure traversal. 159 160 def process_structure_node(self, n): 161 162 "Process the individual node 'n'." 163 164 # Module global detection. 165 166 if isinstance(n, compiler.ast.Global): 167 self.process_global_node(n) 168 169 # Module import declarations. 170 171 elif isinstance(n, compiler.ast.From): 172 self.process_from_node(n) 173 174 elif isinstance(n, compiler.ast.Import): 175 self.process_import_node(n) 176 177 # Nodes using operator module functions. 178 179 elif isinstance(n, compiler.ast.Operator): 180 return self.process_operator_node(n) 181 182 elif isinstance(n, compiler.ast.AugAssign): 183 self.process_augassign_node(n) 184 185 elif isinstance(n, compiler.ast.Compare): 186 return self.process_compare_node(n) 187 188 elif isinstance(n, compiler.ast.Slice): 189 return self.process_slice_node(n) 190 191 elif isinstance(n, compiler.ast.Sliceobj): 192 return self.process_sliceobj_node(n) 193 194 elif isinstance(n, compiler.ast.Subscript): 195 return self.process_subscript_node(n) 196 197 # Namespaces within modules. 198 199 elif isinstance(n, compiler.ast.Class): 200 self.process_class_node(n) 201 202 elif isinstance(n, compiler.ast.Function): 203 self.process_function_node(n, n.name) 204 205 elif isinstance(n, compiler.ast.Lambda): 206 return self.process_lambda_node(n) 207 208 # Assignments. 209 210 elif isinstance(n, compiler.ast.Assign): 211 212 # Handle each assignment node. 213 214 for node in n.nodes: 215 self.process_assignment_node(node, n.expr) 216 217 # Assignments within non-Assign nodes. 218 219 elif isinstance(n, compiler.ast.AssName): 220 self.process_assignment_node(n, None) 221 222 elif isinstance(n, compiler.ast.AssAttr): 223 self.process_attribute_access(n) 224 225 # Accesses. 226 227 elif isinstance(n, compiler.ast.Getattr): 228 return self.process_attribute_access(n) 229 230 # Name recording for later testing. 231 232 elif isinstance(n, compiler.ast.Name): 233 return self.process_name_node(n) 234 235 # Conditional statement tracking. 236 237 elif isinstance(n, compiler.ast.For): 238 self.process_for_node(n) 239 240 elif isinstance(n, compiler.ast.While): 241 self.process_while_node(n) 242 243 elif isinstance(n, compiler.ast.If): 244 self.process_if_node(n) 245 246 elif isinstance(n, (compiler.ast.And, compiler.ast.Or)): 247 return self.process_logical_node(n) 248 249 # Exception control-flow tracking. 250 251 elif isinstance(n, compiler.ast.TryExcept): 252 self.process_try_node(n) 253 254 elif isinstance(n, compiler.ast.TryFinally): 255 self.process_try_finally_node(n) 256 257 # Control-flow modification statements. 258 259 elif isinstance(n, compiler.ast.Break): 260 self.trackers[-1].suspend_broken_branch() 261 262 elif isinstance(n, compiler.ast.Continue): 263 self.trackers[-1].suspend_continuing_branch() 264 265 elif isinstance(n, compiler.ast.Raise): 266 self.process_structure(n) 267 self.trackers[-1].abandon_branch() 268 269 elif isinstance(n, compiler.ast.Return): 270 self.process_structure(n) 271 self.trackers[-1].abandon_returning_branch() 272 273 # Invocations. 274 275 elif isinstance(n, compiler.ast.CallFunc): 276 return self.process_invocation_node(n) 277 278 # Constant usage. 279 280 elif isinstance(n, compiler.ast.Const): 281 return self.get_literal_instance(n, n.value.__class__.__name__) 282 283 elif isinstance(n, compiler.ast.Dict): 284 return self.get_literal_instance(n, "dict") 285 286 elif isinstance(n, compiler.ast.List): 287 return self.get_literal_instance(n, "list") 288 289 elif isinstance(n, compiler.ast.Tuple): 290 return self.get_literal_instance(n, "tuple") 291 292 # List comprehensions and if expressions. 293 294 elif isinstance(n, compiler.ast.ListComp): 295 self.process_listcomp_node(n) 296 297 elif isinstance(n, compiler.ast.IfExp): 298 self.process_ifexp_node(n) 299 300 # All other nodes are processed depth-first. 301 302 else: 303 self.process_structure(n) 304 305 # By default, no expression details are returned. 306 307 return None 308 309 # Specific node handling. 310 311 def process_assignment_node(self, n, expr): 312 313 "Process the individual node 'n' to be assigned the contents of 'expr'." 314 315 # Names and attributes are assigned the entire expression. 316 317 if isinstance(n, compiler.ast.AssName): 318 319 name_ref = expr and self.process_structure_node(expr) 320 321 # Name assignments populate either function namespaces or the 322 # general namespace hierarchy. 323 324 self.assign_general_local(n.name, name_ref) 325 326 # Record usage of the name. 327 328 self.record_name(n.name) 329 330 elif isinstance(n, compiler.ast.AssAttr): 331 if expr: self.process_structure_node(expr) 332 self.process_attribute_access(n) 333 334 # Lists and tuples are matched against the expression and their 335 # items assigned to expression items. 336 337 elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)): 338 self.process_assignment_node_items(n, expr) 339 340 # Slices and subscripts are permitted within assignment nodes. 341 342 elif isinstance(n, compiler.ast.Slice): 343 self.process_slice_node(n, expr) 344 345 elif isinstance(n, compiler.ast.Subscript): 346 self.process_subscript_node(n, expr) 347 348 def process_attribute_access(self, n): 349 350 "Process the given attribute access node 'n'." 351 352 # Obtain any completed chain and return the reference to it. 353 354 name_ref = self.process_attribute_chain(n) 355 if self.have_access_expression(n): 356 return name_ref 357 358 # Where the start of the chain of attributes has been reached, determine 359 # the complete access. 360 361 # Given a non-access node, this chain can be handled in its entirety, 362 # either being name-based and thus an access rooted on a name, or being 363 # based on some other node and thus an anonymous access of some kind. 364 365 path = self.get_namespace_path() 366 367 # Start with the the full attribute chain. 368 369 remaining = self.attrs 370 attrnames = ".".join(remaining) 371 372 # If the accessor cannot be identified, or where attributes 373 # remain in an attribute chain, record the anonymous accesses. 374 375 if not isinstance(name_ref, NameRef): # includes ResolvedNameRef 376 377 assignment = isinstance(n, compiler.ast.AssAttr) 378 379 init_item(self.attr_accesses, path, set) 380 self.attr_accesses[path].add(attrnames) 381 382 self.record_access_details(None, attrnames, assignment) 383 del self.attrs[0] 384 return 385 386 # Name-based accesses will handle the first attribute in a 387 # chain. 388 389 else: 390 attrname = remaining[0] 391 392 # Attribute assignments are used to identify instance attributes. 393 394 if isinstance(n, compiler.ast.AssAttr) and \ 395 self.in_class and self.in_function and n.expr.name == "self": 396 397 self.set_instance_attr(attrname) 398 399 # Record attribute usage using any name local to this namespace, 400 # if assigned in the namespace, or using an external name 401 # (presently just globals within classes). 402 403 name = self.get_name_for_tracking(name_ref.name, name_ref.final()) 404 tracker = self.trackers[-1] 405 406 immediate_access = len(self.attrs) == 1 407 assignment = immediate_access and isinstance(n, compiler.ast.AssAttr) 408 409 del self.attrs[0] 410 411 # Record global-based chains for subsequent resolution. 412 413 is_global = self.in_function and not self.function_locals[path].has_key(name) or \ 414 not self.in_function 415 416 if is_global: 417 self.record_global_access_details(name, attrnames) 418 419 # Make sure the name is being tracked: global names will not 420 # already be initialised in a branch and must be added 421 # explicitly. 422 423 if not tracker.have_name(name): 424 tracker.assign_names([name]) 425 if self.in_function: 426 self.scope_globals[path].add(name) 427 428 # Record attribute usage in the tracker, and record the branch 429 # information for the access. 430 431 branches = tracker.use_attribute(name, attrname) 432 433 if not branches: 434 print >>sys.stderr, "In %s, name %s is accessed using %s before an assignment." % ( 435 path, name, attrname) 436 branches = tracker.use_attribute(name, attrname) 437 438 self.record_branches_for_access(branches, name, attrnames) 439 access_number = self.record_access_details(name, attrnames, assignment) 440 return AccessRef(name, attrnames, access_number) 441 442 def process_class_node(self, n): 443 444 "Process the given class node 'n'." 445 446 path = self.get_namespace_path() 447 448 # To avoid notions of class "versions" where the same definition 449 # might be parameterised with different state and be referenced 450 # elsewhere (as base classes, for example), classes in functions or 451 # conditions are forbidden. 452 453 if self.in_function or self.in_conditional: 454 print >>sys.stderr, "In %s, class %s in function or conditional statement ignored." % ( 455 path, n.name) 456 return 457 458 # Resolve base classes. 459 460 bases = [] 461 462 for base in n.bases: 463 base_class = self.get_class(base) 464 465 if not base_class: 466 print >>sys.stderr, "In %s, class %s has unidentifiable base class: %s" % ( 467 path, n.name, base) 468 return 469 else: 470 bases.append(base_class) 471 472 # Record bases for the class and retain the class name. 473 474 class_name = self.get_object_path(n.name) 475 476 if not bases and class_name != "__builtins__.core.object": 477 ref = self.get_object("__builtins__.object") 478 bases.append(ref) 479 480 self.importer.classes[class_name] = self.classes[class_name] = bases 481 self.importer.subclasses[class_name] = set() 482 self.scope_globals[class_name] = set() 483 484 # Set the definition before entering the namespace rather than 485 # afterwards because methods may reference it. In normal Python, 486 # a class is not accessible until the definition is complete, but 487 # methods can generally reference it since upon being called the 488 # class will already exist. 489 490 self.set_definition(n.name, "<class>") 491 492 in_class = self.in_class 493 self.in_class = class_name 494 self.set_instance_attr("__class__", Reference("<class>", class_name)) 495 self.enter_namespace(n.name) 496 self.set_name("__fn__") # special instantiator attribute 497 self.set_name("__args__") # special instantiator attribute 498 self.assign_general_local("__name__", self.get_constant("str", class_name)) 499 self.process_structure_node(n.code) 500 self.exit_namespace() 501 self.in_class = in_class 502 503 def process_from_node(self, n): 504 505 "Process the given node 'n', importing from another module." 506 507 path = self.get_namespace_path() 508 509 module_name, names = self.get_module_name(n) 510 if module_name == self.name: 511 raise InspectError("Cannot import from the current module.", path, n) 512 513 self.queue_module(module_name) 514 515 # Attempt to obtain the referenced objects. 516 517 for name, alias in n.names: 518 if name == "*": 519 raise InspectError("Only explicitly specified names can be imported from modules.", path, n) 520 521 # Explicit names. 522 523 ref = self.import_name_from_module(name, module_name) 524 value = ResolvedNameRef(alias or name, ref) 525 self.set_general_local(alias or name, value) 526 527 def process_function_node(self, n, name): 528 529 """ 530 Process the given function or lambda node 'n' with the given 'name'. 531 """ 532 533 is_lambda = isinstance(n, compiler.ast.Lambda) 534 535 # Where a function is declared conditionally, use a separate name for 536 # the definition, and assign the definition to the stated name. 537 538 if (self.in_conditional or self.in_function) and not is_lambda: 539 original_name = name 540 name = self.get_lambda_name() 541 else: 542 original_name = None 543 544 # Initialise argument and local records. 545 546 function_name = self.get_object_path(name) 547 548 argnames = self.importer.function_parameters[function_name] = \ 549 self.function_parameters[function_name] = get_argnames(n.argnames) 550 locals = self.function_locals[function_name] = {} 551 552 for argname in argnames: 553 locals[argname] = Reference("<var>") 554 555 globals = self.scope_globals[function_name] = set() 556 557 # Process the defaults. 558 559 defaults = self.importer.function_defaults[function_name] = \ 560 self.function_defaults[function_name] = [] 561 562 for argname, default in compiler.ast.get_defaults(n): 563 if default: 564 565 # Obtain any reference for the default. 566 567 name_ref = self.process_structure_node(default) 568 defaults.append((argname, name_ref.is_name() and name_ref.reference() or Reference("<var>"))) 569 570 # Reset conditional tracking to focus on the function contents. 571 572 parent_function = self.parent_function 573 self.parent_function = self.in_function and self.get_namespace_path() or None 574 575 in_conditional = self.in_conditional 576 self.in_conditional = False 577 578 in_function = self.in_function 579 self.in_function = function_name 580 581 self.enter_namespace(name) 582 583 # Track attribute usage within the namespace. 584 585 path = self.get_namespace_path() 586 init_item(self.propagated_names, path, set) 587 588 self.start_tracking(locals) 589 self.process_structure_node(n.code) 590 self.stop_tracking() 591 592 # Propagate names from parent scopes. 593 594 for local in self.propagated_names[path]: 595 if not local in argnames and self.trackers[-1].have_name(local): 596 argnames.append(local) 597 defaults.append((local, Reference("<var>"))) 598 self.set_function_local(local) 599 600 # Exit to the parent and note propagated names. 601 602 self.exit_namespace() 603 604 parent = self.get_namespace_path() 605 if self.propagated_names.has_key(parent): 606 for local in self.propagated_names[path]: 607 self.propagated_names[parent].add(local) 608 609 # Update flags. 610 611 self.in_function = in_function 612 self.in_conditional = in_conditional 613 self.parent_function = parent_function 614 615 # Define the function using the appropriate name. 616 617 self.set_definition(name, "<function>") 618 619 # Where a function is set conditionally, assign the name. 620 621 if original_name: 622 self.process_assignment_for_function(original_name, name) 623 624 def process_global_node(self, n): 625 626 """ 627 Process the given "global" node 'n'. 628 """ 629 630 path = self.get_namespace_path() 631 632 if path != self.name: 633 self.scope_globals[path].update(n.names) 634 635 def process_if_node(self, n): 636 637 """ 638 Process the given "if" node 'n'. 639 """ 640 641 tracker = self.trackers[-1] 642 tracker.new_branchpoint() 643 644 for test, body in n.tests: 645 self.process_structure_node(test) 646 647 tracker.new_branch() 648 649 in_conditional = self.in_conditional 650 self.in_conditional = True 651 self.process_structure_node(body) 652 self.in_conditional = in_conditional 653 654 tracker.shelve_branch() 655 656 # Maintain a branch for the else clause. 657 658 tracker.new_branch() 659 if n.else_: 660 self.process_structure_node(n.else_) 661 tracker.shelve_branch() 662 663 tracker.merge_branches() 664 665 def process_ifexp_node(self, n): 666 667 "Process the given if expression node 'n'." 668 669 name_ref = self.process_structure_node(self.convert_ifexp_node(n)) 670 671 path = self.get_namespace_path() 672 self.allocate_arguments(path, self.function_defaults[name_ref.get_origin()]) 673 self.deallocate_arguments(path, self.function_defaults[name_ref.get_origin()]) 674 675 return InvocationRef(name_ref) 676 677 def process_import_node(self, n): 678 679 "Process the given import node 'n'." 680 681 path = self.get_namespace_path() 682 683 # Load the mentioned module. 684 685 for name, alias in n.names: 686 if name == self.name: 687 raise InspectError("Cannot import the current module.", path, n) 688 if not alias and len(n.names) > 1: 689 raise InspectError("Imported modules must be aliased unless a simple module is imported.", path, n) 690 691 self.set_module(alias or name.split(".")[-1], name) 692 self.queue_module(name, True) 693 694 def process_invocation_node(self, n): 695 696 "Process the given invocation node 'n'." 697 698 path = self.get_namespace_path() 699 700 self.allocate_arguments(path, n.args) 701 702 try: 703 # Process the expression, obtaining any identified reference. 704 705 name_ref = self.process_structure_node(n.node) 706 707 # Process the arguments. 708 709 for arg in n.args: 710 self.process_structure_node(arg) 711 712 # Detect class invocations. 713 714 if isinstance(name_ref, ResolvedNameRef) and name_ref.has_kind("<class>"): 715 return InstanceRef(name_ref.reference().instance_of()) 716 717 elif isinstance(name_ref, NameRef): 718 return InvocationRef(name_ref) 719 720 return None 721 722 finally: 723 self.deallocate_arguments(path, n.args) 724 725 def process_lambda_node(self, n): 726 727 "Process the given lambda node 'n'." 728 729 name = self.get_lambda_name() 730 self.process_function_node(n, name) 731 732 origin = self.get_object_path(name) 733 return ResolvedNameRef(name, Reference("<function>", origin)) 734 735 def process_listcomp_node(self, n): 736 737 "Process the given list comprehension node 'n'." 738 739 name_ref = self.process_structure_node(self.convert_listcomp_node(n)) 740 741 path = self.get_namespace_path() 742 self.allocate_arguments(path, self.function_defaults[name_ref.get_origin()]) 743 self.deallocate_arguments(path, self.function_defaults[name_ref.get_origin()]) 744 745 return InvocationRef(name_ref) 746 747 def process_logical_node(self, n): 748 749 "Process the given operator node 'n'." 750 751 self.process_operator_chain(n.nodes, self.process_structure_node) 752 753 def process_name_node(self, n): 754 755 "Process the given name node 'n'." 756 757 path = self.get_namespace_path() 758 759 # Special names. 760 761 if n.name.startswith("$"): 762 value = self.get_special(n.name) 763 if value: 764 return value 765 766 # Special case for operator functions introduced through code 767 # transformations. 768 769 if n.name.startswith("$op"): 770 771 # Obtain the location of the actual function defined in the operator 772 # package. 773 774 op = n.name[len("$op"):] 775 776 # Attempt to get a reference. 777 778 ref = self.import_name_from_module(op, "operator") 779 self.add_deferred(ref) 780 781 # Record the imported name and provide the resolved name reference. 782 783 value = ResolvedNameRef(n.name, ref) 784 self.set_special(n.name, value) 785 return value 786 787 # Record usage of the name. 788 789 self.record_name(n.name) 790 791 # Search for unknown names in non-function scopes immediately. 792 # External names in functions are resolved later. 793 794 ref = self.find_name(n.name) 795 if ref: 796 return ResolvedNameRef(n.name, ref) 797 798 # Global name. 799 800 elif self.in_function and n.name in self.scope_globals[path]: 801 return NameRef(n.name) 802 803 # Examine other names. 804 805 else: 806 tracker = self.trackers[-1] 807 808 # Check local names. 809 810 branches = tracker.tracking_name(n.name) 811 812 # Find names inherited from a parent scope. 813 814 if not branches and self.parent_function: 815 branches = tracker.have_name(n.name) 816 if branches: 817 self.propagate_name(n.name) 818 819 # Local or inherited name. 820 821 if branches: 822 self.record_branches_for_access(branches, n.name, None) 823 access_number = self.record_access_details(n.name, None, False) 824 return LocalNameRef(n.name, access_number) 825 826 # Possible global name. 827 828 else: 829 return NameRef(n.name) 830 831 def process_operator_chain(self, nodes, fn): 832 833 """ 834 Process the given chain of 'nodes', applying 'fn' to each node or item. 835 Each node starts a new conditional region, effectively making a deeply- 836 nested collection of if-like statements. 837 """ 838 839 tracker = self.trackers[-1] 840 841 for item in nodes: 842 tracker.new_branchpoint() 843 tracker.new_branch() 844 fn(item) 845 846 for item in nodes[:-1]: 847 tracker.shelve_branch() 848 tracker.new_branch() 849 tracker.shelve_branch() 850 tracker.merge_branches() 851 852 tracker.shelve_branch() 853 tracker.merge_branches() 854 855 def process_try_node(self, n): 856 857 """ 858 Process the given "try...except" node 'n'. 859 """ 860 861 tracker = self.trackers[-1] 862 tracker.new_branchpoint() 863 864 self.process_structure_node(n.body) 865 866 for name, var, handler in n.handlers: 867 if name is not None: 868 self.process_structure_node(name) 869 870 # Any abandoned branches from the body can now be resumed in a new 871 # branch. 872 873 tracker.resume_abandoned_branches() 874 875 # Establish the local for the handler. 876 877 if var is not None: 878 self.process_structure_node(var) 879 if handler is not None: 880 self.process_structure_node(handler) 881 882 tracker.shelve_branch() 883 884 # The else clause maintains the usage from the body but without the 885 # abandoned branches since they would never lead to the else clause 886 # being executed. 887 888 if n.else_: 889 tracker.new_branch() 890 self.process_structure_node(n.else_) 891 tracker.shelve_branch() 892 893 # Without an else clause, a null branch propagates the successful 894 # outcome. 895 896 else: 897 tracker.new_branch() 898 tracker.shelve_branch() 899 900 tracker.merge_branches() 901 902 def process_try_finally_node(self, n): 903 904 """ 905 Process the given "try...finally" node 'n'. 906 """ 907 908 tracker = self.trackers[-1] 909 self.process_structure_node(n.body) 910 911 # Any abandoned branches from the body can now be resumed. 912 913 branches = tracker.resume_all_abandoned_branches() 914 self.process_structure_node(n.final) 915 916 # At the end of the finally clause, abandoned branches are discarded. 917 918 tracker.restore_active_branches(branches) 919 920 def process_while_node(self, n): 921 922 "Process the given while node 'n'." 923 924 tracker = self.trackers[-1] 925 tracker.new_branchpoint(loop_node=True) 926 927 # Evaluate any test or iterator outside the loop. 928 929 self.process_structure_node(n.test) 930 931 # Propagate attribute usage to branches. 932 933 tracker.new_branch(loop_node=True) 934 935 # Enter the loop. 936 937 in_conditional = self.in_conditional 938 self.in_conditional = True 939 self.process_structure_node(n.body) 940 self.in_conditional = in_conditional 941 942 # Continuing branches are resumed before any test. 943 944 tracker.resume_continuing_branches() 945 946 # Evaluate any continuation test within the body. 947 948 self.process_structure_node(n.test) 949 950 tracker.shelve_branch(loop_node=True) 951 952 # Support the non-looping condition. 953 954 tracker.new_branch() 955 tracker.shelve_branch() 956 957 tracker.merge_branches() 958 959 # Evaluate any else clause outside branches. 960 961 if n.else_: 962 self.process_structure_node(n.else_) 963 964 # Connect broken branches to the code after any loop. 965 966 tracker.resume_broken_branches() 967 968 # Branch tracking methods. 969 970 def start_tracking(self, names): 971 972 """ 973 Start tracking attribute usage for names in the current namespace, 974 immediately registering the given 'names'. 975 """ 976 977 path = self.get_namespace_path() 978 parent = self.trackers[-1] 979 tracker = BranchTracker() 980 self.trackers.append(tracker) 981 982 # For functions created from expressions or for functions within 983 # functions, propagate usage to the new namespace. 984 985 if self.parent_function: 986 tracker.inherit_branches(parent, names) 987 988 # Record the given names established as new branches. 989 990 tracker.assign_names(names) 991 992 def assign_name(self, name, name_ref): 993 994 "Assign to 'name' the given 'name_ref' in the current namespace." 995 996 name = self.get_name_for_tracking(name) 997 self.trackers[-1].assign_names([name], [name_ref]) 998 999 def stop_tracking(self): 1000 1001 """ 1002 Stop tracking attribute usage, recording computed usage for the current 1003 namespace. 1004 """ 1005 1006 path = self.get_namespace_path() 1007 tracker = self.trackers.pop() 1008 self.record_assignments_for_access(tracker) 1009 1010 self.attr_usage[path] = tracker.get_all_usage() 1011 self.name_initialisers[path] = tracker.get_all_values() 1012 1013 def start_tracking_in_module(self): 1014 1015 "Start tracking attribute usage in the module." 1016 1017 tracker = BranchTracker() 1018 self.trackers.append(tracker) 1019 1020 def stop_tracking_in_module(self): 1021 1022 "Stop tracking attribute usage in the module." 1023 1024 tracker = self.trackers[0] 1025 self.record_assignments_for_access(tracker) 1026 self.attr_usage[self.name] = tracker.get_all_usage() 1027 self.name_initialisers[self.name] = tracker.get_all_values() 1028 1029 def propagate_name(self, name): 1030 1031 "Propagate the given 'name' into the current namespace." 1032 1033 path = self.get_namespace_path() 1034 self.propagated_names[path].add(name) 1035 1036 def record_assignments_for_access(self, tracker): 1037 1038 """ 1039 For the current path, use the given 'tracker' to record assignment 1040 version information for attribute accesses. 1041 """ 1042 1043 path = self.get_path_for_access() 1044 1045 if not self.attr_accessor_branches.has_key(path): 1046 return 1047 1048 init_item(self.attr_accessors, path, dict) 1049 attr_accessors = self.attr_accessors[path] 1050 1051 # Obtain the branches applying during each access. 1052 1053 for access, all_branches in self.attr_accessor_branches[path].items(): 1054 name, attrnames = access 1055 init_item(attr_accessors, access, list) 1056 1057 # Obtain the assignments applying to each branch. 1058 1059 for branches in all_branches: 1060 positions = tracker.get_assignment_positions_for_branches(name, branches) 1061 1062 # Detect missing name information. 1063 1064 if None in positions: 1065 globals = self.global_attr_accesses.get(path) 1066 accesses = globals and globals.get(name) 1067 if not accesses: 1068 print >>sys.stderr, "In %s, %s may not be defined when used." % ( 1069 self.get_namespace_path(), name) 1070 positions.remove(None) 1071 1072 attr_accessors[access].append(positions) 1073 1074 def record_branches_for_access(self, branches, name, attrnames): 1075 1076 """ 1077 Record the given 'branches' for an access involving the given 'name' and 1078 'attrnames'. 1079 """ 1080 1081 access = name, attrnames 1082 path = self.get_path_for_access() 1083 1084 init_item(self.attr_accessor_branches, path, dict) 1085 attr_accessor_branches = self.attr_accessor_branches[path] 1086 1087 init_item(attr_accessor_branches, access, list) 1088 attr_accessor_branches[access].append(branches) 1089 1090 def record_access_details(self, name, attrnames, assignment): 1091 1092 """ 1093 For the given 'name' and 'attrnames', record an access indicating 1094 whether 'assignment' is occurring. 1095 1096 These details correspond to accesses otherwise recorded by the attribute 1097 accessor and attribute access dictionaries. 1098 """ 1099 1100 access = name, attrnames 1101 path = self.get_path_for_access() 1102 1103 init_item(self.attr_access_modifiers, path, dict) 1104 init_item(self.attr_access_modifiers[path], access, list) 1105 1106 access_number = len(self.attr_access_modifiers[path][access]) 1107 self.attr_access_modifiers[path][access].append(assignment) 1108 return access_number 1109 1110 def record_global_access_details(self, name, attrnames): 1111 1112 """ 1113 Record details of a global access via the given 'name' involving the 1114 indicated 'attrnames'. 1115 """ 1116 1117 path = self.get_namespace_path() 1118 1119 init_item(self.global_attr_accesses, path, dict) 1120 init_item(self.global_attr_accesses[path], name, set) 1121 self.global_attr_accesses[path][name].add(attrnames) 1122 1123 # Namespace modification. 1124 1125 def record_name(self, name): 1126 1127 "Record the use of 'name' in a namespace." 1128 1129 path = self.get_namespace_path() 1130 init_item(self.names_used, path, set) 1131 self.names_used[path].add(name) 1132 1133 def set_module(self, name, module_name): 1134 1135 """ 1136 Set a module in the current namespace using the given 'name' associated 1137 with the corresponding 'module_name'. 1138 """ 1139 1140 if name: 1141 self.set_general_local(name, Reference("<module>", module_name)) 1142 1143 def set_definition(self, name, kind): 1144 1145 """ 1146 Set the definition having the given 'name' and 'kind'. 1147 1148 Definitions are set in the static namespace hierarchy, but they can also 1149 be recorded for function locals. 1150 """ 1151 1152 if self.is_global(name): 1153 print >>sys.stderr, "In %s, %s is defined as being global." % ( 1154 self.get_namespace_path(), name) 1155 1156 path = self.get_object_path(name) 1157 self.set_object(path, kind) 1158 1159 ref = self.get_object(path) 1160 if ref.get_kind() == "<var>": 1161 print >>sys.stderr, "In %s, %s is defined more than once." % ( 1162 self.get_namespace_path(), name) 1163 1164 if not self.is_global(name) and self.in_function: 1165 self.set_function_local(name, ref) 1166 1167 def set_function_local(self, name, ref=None): 1168 1169 "Set the local with the given 'name' and optional 'ref'." 1170 1171 locals = self.function_locals[self.get_namespace_path()] 1172 multiple = not ref or locals.has_key(name) and locals[name] != ref 1173 locals[name] = multiple and Reference("<var>") or ref 1174 1175 def assign_general_local(self, name, name_ref): 1176 1177 """ 1178 Set for 'name' the given 'name_ref', recording the name for attribute 1179 usage tracking. 1180 """ 1181 1182 self.set_general_local(name, name_ref) 1183 self.assign_name(name, name_ref) 1184 1185 def set_general_local(self, name, value=None): 1186 1187 """ 1188 Set the 'name' with optional 'value' in any kind of local namespace, 1189 where the 'value' should be a reference if specified. 1190 """ 1191 1192 init_value = self.get_initialising_value(value) 1193 1194 # Module global names. 1195 1196 if self.is_global(name): 1197 path = self.get_global_path(name) 1198 self.set_object(path, init_value) 1199 1200 # Function local names. 1201 1202 elif self.in_function: 1203 path = self.get_object_path(name) 1204 self.set_function_local(name, init_value) 1205 1206 # Other namespaces (classes). 1207 1208 else: 1209 path = self.get_object_path(name) 1210 self.set_name(name, init_value) 1211 1212 def set_name(self, name, ref=None): 1213 1214 "Attach the 'name' with optional 'ref' to the current namespace." 1215 1216 self.set_object(self.get_object_path(name), ref) 1217 1218 def set_instance_attr(self, name, ref=None): 1219 1220 """ 1221 Add an instance attribute of the given 'name' to the current class, 1222 using the optional 'ref'. 1223 """ 1224 1225 init_item(self.instance_attrs, self.in_class, set) 1226 self.instance_attrs[self.in_class].add(name) 1227 1228 if ref: 1229 init_item(self.instance_attr_constants, self.in_class, dict) 1230 self.instance_attr_constants[self.in_class][name] = ref 1231 1232 def get_initialising_value(self, value): 1233 1234 "Return a suitable initialiser reference for 'value'." 1235 1236 # Includes LiteralSequenceRef, ResolvedNameRef... 1237 1238 if isinstance(value, (NameRef, AccessRef, InstanceRef)): 1239 return value.reference() 1240 1241 # In general, invocations do not produce known results. However, the 1242 # name initialisers are resolved once a module has been inspected. 1243 1244 elif isinstance(value, InvocationRef): 1245 return value.reference() 1246 1247 else: 1248 return value 1249 1250 # Static, program-relative naming. 1251 1252 def find_name(self, name): 1253 1254 """ 1255 Return the qualified name for the given 'name' used in the current 1256 non-function namespace. 1257 """ 1258 1259 path = self.get_namespace_path() 1260 ref = None 1261 1262 if not self.in_function and name not in predefined_constants: 1263 if self.in_class: 1264 ref = self.get_object(self.get_object_path(name)) 1265 if not ref: 1266 ref = self.get_global_or_builtin(name) 1267 1268 return ref 1269 1270 def get_class(self, node): 1271 1272 """ 1273 Use the given 'node' to obtain the identity of a class. Return a 1274 reference for the class. Unresolved dependencies are permitted and must 1275 be resolved later. 1276 """ 1277 1278 ref = self._get_class(node) 1279 return ref.has_kind(["<class>", "<depends>"]) and ref or None 1280 1281 def _get_class(self, node): 1282 1283 """ 1284 Use the given 'node' to find a class definition. Return a reference to 1285 the class. 1286 """ 1287 1288 if isinstance(node, compiler.ast.Getattr): 1289 1290 # Obtain the identity of the access target. 1291 1292 ref = self._get_class(node.expr) 1293 1294 # Where the target is a class or module, obtain the identity of the 1295 # attribute. 1296 1297 if ref.has_kind(["<function>", "<var>"]): 1298 return None 1299 else: 1300 attrname = "%s.%s" % (ref.get_origin(), node.attrname) 1301 return self.get_object(attrname) 1302 1303 # Names can be module-level or built-in. 1304 1305 elif isinstance(node, compiler.ast.Name): 1306 1307 # Record usage of the name and attempt to identify it. 1308 1309 self.record_name(node.name) 1310 return self.get_global_or_builtin(node.name) 1311 else: 1312 return None 1313 1314 def get_constant(self, name, value): 1315 1316 "Return a constant reference for the given type 'name' and 'value'." 1317 1318 ref = self.get_builtin_class(name) 1319 return self.get_constant_reference(ref, value) 1320 1321 def get_literal_instance(self, n, name): 1322 1323 "For node 'n', return a reference to an instance of 'name'." 1324 1325 # Get a reference to the built-in class. 1326 1327 ref = self.get_builtin_class(name) 1328 1329 # Obtain the details of the literal itself. 1330 # An alias to the type is generated for sequences. 1331 1332 if name in ("dict", "list", "tuple"): 1333 self.set_special_literal(name, ref) 1334 return self.process_literal_sequence_node(n, name, ref, LiteralSequenceRef) 1335 1336 # Constant values are independently recorded. 1337 1338 else: 1339 return self.get_constant_reference(ref, n.value) 1340 1341 # Special names. 1342 1343 def get_special(self, name): 1344 1345 "Return any stored value for the given special 'name'." 1346 1347 return self.special.get(name) 1348 1349 def set_special(self, name, value): 1350 1351 """ 1352 Set a special 'name' that merely tracks the use of an implicit object 1353 'value'. 1354 """ 1355 1356 self.special[name] = value 1357 1358 def set_special_literal(self, name, ref): 1359 1360 """ 1361 Set a special name for the literal type 'name' having type 'ref'. Such 1362 special names provide a way of referring to literal object types. 1363 """ 1364 1365 literal_name = "$L%s" % name 1366 value = ResolvedNameRef(literal_name, ref) 1367 self.set_special(literal_name, value) 1368 1369 # Functions and invocations. 1370 1371 def set_invocation_usage(self): 1372 1373 """ 1374 Discard the current invocation storage figures, retaining the maximum 1375 values. 1376 """ 1377 1378 for path, (current, maximum) in self.function_targets.items(): 1379 self.importer.function_targets[path] = self.function_targets[path] = maximum 1380 1381 for path, (current, maximum) in self.function_arguments.items(): 1382 self.importer.function_arguments[path] = self.function_arguments[path] = maximum 1383 1384 def allocate_arguments(self, path, args): 1385 1386 """ 1387 Allocate temporary argument storage using current and maximum 1388 requirements for the given 'path' and 'args'. 1389 """ 1390 1391 init_item(self.function_targets, path, lambda: [0, 0]) 1392 t = self.function_targets[path] 1393 t[0] += 1 1394 t[1] = max(t[0], t[1]) 1395 1396 init_item(self.function_arguments, path, lambda: [0, 0]) 1397 t = self.function_arguments[path] 1398 t[0] += len(args) + 1 1399 t[1] = max(t[0], t[1]) 1400 1401 def deallocate_arguments(self, path, args): 1402 1403 "Deallocate temporary argument storage for the given 'path' and 'args'." 1404 1405 self.function_targets[path][0] -= 1 1406 self.function_arguments[path][0] -= len(args) + 1 1407 1408 # vim: tabstop=4 expandtab shiftwidth=4