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