Lichen

inspector.py

656:cb4fd280007e
2017-03-05 Paul Boddie Avoid unnecessary work by testing for the True value before any bool invocation.
     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