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