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