Lichen

inspector.py

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