micropython

micropython/inspect.py

598:d13e02292ffa
2012-07-14 Paul Boddie Record unsatisfiable usage observations for potential later display as warnings.
     1 #!/usr/bin/env python     2      3 """     4 Inspect source files, obtaining details of classes and attributes.     5      6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20     21 --------    22     23 The results of inspecting a module are as follows:    24     25 Constants    26 ---------    27     28 All constants identified within the code shall be registered.    29     30 Classes    31 -------    32     33 All global classes shall be registered; local classes (within functions) or    34 nested classes (within classes) are not currently registered.    35     36 Base classes must be detected and constant.    37     38 All classes without bases are made to inherit from __builtins__.object in order    39 to support some standard methods.    40     41 Functions    42 ---------    43     44 All functions and lambda definitions shall be registered.    45     46 Namespaces    47 ----------    48     49 Modules define their own "global" namespace, within which classes, functions    50 and lambda definitions establish a hierarchy of namespaces.    51     52 Only local, global and built-in namespaces are recognised; closures are not    53 supported.    54     55 Assignments    56 -----------    57     58 Name assignment and attribute assignment involving modules and classes cause    59 names to be associated with values within namespaces.    60     61 Any assignments within loops are considered to cause the targets of such    62 assignments to provide non-constant values.    63     64 Assignments to names are only really considered to cause the targets of such    65 assignments to provide constant values if the targets reside in class    66 namespaces, subject to the above conditions.    67     68 Assignments to names within functions are not generally considered to cause the    69 targets of such assignments to provide constant values since functions can be    70 invoked many times with different inputs. This affects particularly the    71 definition of functions or lambdas within functions. However, there may be    72 benefits in considering a local to be constant within a single invocation.    73 """    74     75 from micropython.common import *    76 from micropython.data import *    77 from micropython.errors import *    78 import compiler.ast    79 import sys    80     81 # Program visitors.    82     83 class InspectedModule(ASTVisitor, Module):    84     85     """    86     An inspected module, providing core details via the Module superclass, but    87     capable of being used as an AST visitor.    88     89     A module can be inspected through the invocation of the following methods in    90     order:    91     92      1. parse    93      2. process    94      3. vacuum    95      4. finalise    96     97     A module importer can be expected to perform these invocations.    98     """    99    100     def __init__(self, name, importer):   101    102         """   103         Initialise this visitor with a module 'name' and an 'importer' which is   104         used to provide access to other modules when required.   105         """   106    107         Module.__init__(self, name, importer)   108         self.visitor = self   109    110         # Import machinery links.   111    112         self.optimisations = self.importer.optimisations   113         self.builtins = self.importer.modules.get("__builtins__")   114         self.loaded = False   115         self.completed = False   116    117         # Current expression state.   118    119         self.expr = None   120         self.in_assignment = False  # For slice and subscript handling.   121    122         # Namespace state.   123    124         self.in_method = False      # Find instance attributes in all methods.   125         self.in_function = False    # Note function presence, affecting definitions.   126         self.in_loop = False        # Note loop "membership", affecting assignments.   127         self.namespaces = []   128         self.functions = []   129    130     def parse(self, filename):   131    132         "Parse the file having the given 'filename'."   133    134         self.astnode = module = compiler.parseFile(filename)   135    136         # Detect and record imports and globals declared in the module.   137    138         self.process_structure(module)   139    140     def complete(self):   141         if not self.completed:   142             self.completed = True   143             self.process()   144             if self.importer.verbose:   145                 print >>sys.stderr, "Completed import of", self.full_name()   146    147     def process(self):   148         return self.process_module(self.astnode)   149    150     def process_module(self, module):   151    152         """   153         Process the given 'module', visiting module-level code and function   154         code.   155         """   156    157         # Add __name__ to the namespace.   158    159         self.store("__name__", self._visitConst(self.full_name()))   160    161         # Visit module-level code, also recording global names.   162    163         processed = self.dispatch(module)   164    165         self.finalise_attribute_usage()   166    167         # Visit functions.   168    169         self.process_functions()   170    171         # Add references to other modules declared using the __all__ global.   172    173         if self.has_key("__all__"):   174             all = self["__all__"]   175             if isinstance(all, compiler.ast.List):   176                 for n in all.nodes:   177                     self.store(n.value, self.importer.add_module(self.name + "." + n.value))   178    179         return processed   180    181     def process_functions(self):   182    183         """   184         Process all function bodies. Deferred imports may occur during this   185         process.   186         """   187    188         # Then, visit each function, recording other names. This happens to   189         # work for lambda definitions inside functions since they are added to   190         # the end of self.functions and are thus visited as the iteration   191         # reaches the end of the original list.   192    193         for node, namespaces in self.functions:   194             self._visitFunctionBody(node, namespaces)   195             namespaces[-1].finalise_attribute_usage()   196    197     def process_structure(self, node):   198    199         """   200         Within the given 'node', process global declarations, adjusting the   201         module namespace, and import statements, building a module dependency   202         hierarchy.   203         """   204    205         for n in node.getChildNodes():   206    207             # Module global detection.   208    209             if isinstance(n, compiler.ast.Global):   210                 for name in n.names:   211    212                     # Each name may potentially be assigned many times.   213                     # We don't try and find out the specifics at this point and   214                     # just indicate that the name cannot be relied upon for   215                     # various observations.   216    217                     self.modify_name(name)   218    219             # Module import declarations.   220    221             elif isinstance(n, compiler.ast.From):   222    223                 # Load the mentioned module.   224    225                 self.record_import(n.modname, n)   226    227                 # Speculatively load modules for names beneath the module.   228    229                 for name, alias in n.names:   230                     modname = n.modname + "." + name   231                     self.record_import(modname, n)   232    233             elif isinstance(n, compiler.ast.Import):   234    235                 # Load the mentioned module.   236    237                 for name, alias in n.names:   238                     self.record_import(name, n)   239    240             # Nodes using operator module functions.   241    242             elif operator_functions.has_key(n.__class__.__name__) or \   243                 isinstance(n, (compiler.ast.AugAssign, compiler.ast.Compare)):   244    245                 n._module = self.importer.load("operator")   246    247             else:   248                 self.process_structure(n)   249    250     def get_module_paths(self, name):   251    252         """   253         Return the paths of modules leading to the module having the given   254         'name'.   255         """   256    257         names = []   258         parts = []   259         for part in name.split("."):   260             parts.append(part)   261             names.append(".".join(parts))   262         return names   263    264     def record_import(self, name, node):   265    266         """   267         Record an import of a module with the given 'name' occurring at the   268         given 'node'.   269         """   270    271         module = self.importer.load(name, 1, importer=node)   272         if module and not module.loaded:   273             self.importer.circular_imports.add(module)   274    275     def complete_import(self, name, return_leaf):   276    277         """   278         Complete the import of the module with the given 'name', returning the   279         module itself if 'return_leaf' is a true value, or returning the root of   280         the module hierarchy if 'return_leaf' is a false value.   281         """   282    283         top = module = None   284    285         for modname in self.get_module_paths(name):   286    287             # Attempt to get the module, returning None for non-existent   288             # modules.   289    290             try:   291                 module = self.importer.get_module(modname)   292             except KeyError:   293                 return None   294    295             if module:   296                 module.complete()   297    298             if top is None:   299                 top = module   300    301         if return_leaf:   302             return module   303         else:   304             return top   305    306     def vacuum(self):   307    308         """   309         Vacuum the module namespace, removing unreferenced objects and unused   310         names.   311         """   312    313         if self.should_optimise_unused_objects():   314             self.vacuum_object(self)   315    316             all_objects = list(self.all_objects)   317    318             for obj in all_objects:   319                 self.vacuum_object(obj)   320    321     def vacuum_object(self, obj, delete_all=0):   322    323         "Vacuum the given object 'obj'."   324    325         # Get all constant objects in apparent use.   326    327         if delete_all:   328             obj_objects = set()   329         else:   330             obj_objects = []   331             for name, attr in obj.items_for_vacuum():   332    333                 # Get constant objects for attributes in use.   334    335                 if self.importer.uses_attribute(obj.full_name(), name) and \   336                     attr is not None and attr.is_constant():   337    338                     value = attr.get_value()   339                     obj_objects.append(value)   340    341         # Now vacuum unused attributes and objects not in use.   342    343         for name, attr in obj.items_for_vacuum():   344    345             # Only consider deleting entire unused objects or things accessible   346             # via names which are never used.   347    348             if delete_all or not self.importer.uses_attribute(obj.full_name(), name):   349                 obj.vacuum_item(name)   350    351                 # Delete any unambiguous attribute value. Such values can only   352                 # have been defined within the object and therefore are not   353                 # redefined by other code regions.   354    355                 if attr is not None and attr.is_constant():   356                     value = attr.get_value()   357    358                     # The value must have this object as a parent.   359                     # However, it must not be shared by several names.   360    361                     if value is not obj and value.parent is obj and \   362                         value in self.all_objects and value not in obj_objects:   363    364                         self.all_objects.remove(value)   365    366                         # Delete class contents and lambdas from functions.   367    368                         self.vacuum_object(value, 1)   369    370     def unfinalise(self):   371    372         "Reset finalised information for the module."   373    374         for obj in self.all_objects:   375             obj.unfinalise_attributes()   376    377     def finalise(self, objtable):   378    379         "Finalise the module."   380    381         for obj in self.all_objects:   382             obj.finalise(objtable)   383    384         self.finalise_users(objtable)   385    386     def add_object(self, obj, any_scope=0):   387    388         """   389         Record 'obj' if non-local or if the optional 'any_scope' is set to a   390         true value.   391         """   392    393         if any_scope or not (self.namespaces and isinstance(self.namespaces[-1], Function)):   394             self.all_objects.add(obj)   395    396     # Optimisation tests.   397    398     def should_optimise_unused_objects(self):   399         return "unused_objects" in self.optimisations   400    401     # Namespace methods.   402    403     def in_class(self, namespaces=None):   404         namespaces = namespaces or self.namespaces   405         return len(namespaces) > 1 and isinstance(namespaces[-2], Class)   406    407     def store(self, name, obj):   408    409         "Record attribute or local 'name', storing 'obj'."   410    411         # Store in the module.   412    413         if not self.namespaces:   414             if self.in_loop and self.used_in_scope(name, "builtins"):   415                 raise InspectError("Name %r already used as a built-in." % name)   416             else:   417                 self.set(name, obj, not self.in_loop)   418    419         # Or store locally.   420    421         else:   422             locals = self.namespaces[-1]   423    424             if self.in_loop and locals.used_in_scope(name, "global") and not name in locals.globals:   425                 raise InspectError("Name %r already used as global." % name)   426             elif self.in_loop and locals.used_in_scope(name, "builtins"):   427                 raise InspectError("Name %r already used as a built-in." % name)   428             else:   429                 locals.set(name, obj, not self.in_loop)   430    431     def store_lambda(self, obj):   432    433         "Store a lambda function 'obj'."   434    435         self.add_object(obj)   436         self.get_namespace().add_lambda(obj)   437    438     def store_module_attr(self, name, module):   439    440         """   441         Record module attribute 'name' in the given 'module' using the current   442         expression.   443         """   444    445         module.set(name, self.expr, 0)   446         self.use_specific_attribute(module.full_name(), name)   447    448     def store_class_attr(self, name, cls):   449    450         """   451         Record class attribute 'name' in the given class 'cls' using the current   452         expression.   453         """   454    455         cls.set(name, self.expr, 0)   456         self.use_specific_attribute(cls.full_name(), name)   457    458     def store_instance_attr(self, name, tentative=False):   459    460         """   461         Record instance attribute 'name' in the current class. If 'tentative' is   462         set to a true value, the instance attribute will be discarded if a class   463         attribute is observed.   464         """   465    466         if self.in_method:   467    468             # Current namespace is the function.   469             # Previous namespace is the class.   470    471             cls = self.namespaces[-2]   472             cls.add_instance_attribute(name, tentative)   473    474             # NOTE: The instance attribute, although defined in a specific   475             # NOTE: class, obviously appears in all descendant classes.   476    477             self.use_specific_attribute(cls.full_name(), name)   478    479     def get_namespace(self):   480    481         "Return the parent (or most recent) namespace currently exposed."   482    483         return (self.namespaces[-1:] or [self])[0]   484    485     def use_name(self, name, node=None, value=None, ns=None):   486    487         """   488         Use the given 'name' within the current namespace/unit, either in   489         conjunction with a particular object (if 'node' is specified and not   490         None) or unconditionally.   491         """   492    493         unit = self.get_namespace()   494    495         # Handle attribute usage situations within the current unit.   496    497         if node is not None and isinstance(node, compiler.ast.Name) and ns is unit:   498             self.use_attribute(node.name, name, value)   499    500         # For general name usage, declare usage of the given name from this   501         # particular unit.   502    503         else:   504             self.importer.use_name(name, unit.full_name(), value)   505    506     def use_constant(self, const):   507    508         "Use the given 'const' within the current namespace/unit."   509    510         unit = self.get_namespace()   511         self.importer.use_constant(const, unit.full_name())   512    513     # Attribute usage methods.   514     # These are convenience methods which refer to the specific namespace's   515     # implementation of these operations.   516    517     def new_branchpoint(self, loop_node=None):   518         self.get_namespace()._new_branchpoint(loop_node)   519    520     def new_branch(self, node):   521         self.get_namespace()._new_branch(node)   522    523     def abandon_branch(self):   524         self.get_namespace()._abandon_branch()   525    526     def suspend_broken_branch(self):   527         self.get_namespace()._suspend_broken_branch()   528    529     def suspend_continuing_branch(self):   530         self.get_namespace()._suspend_continuing_branch()   531    532     def shelve_branch(self):   533         self.get_namespace()._shelve_branch()   534    535     def merge_branches(self):   536         self.get_namespace()._merge_branches()   537    538     def resume_broken_branches(self):   539         self.get_namespace()._resume_broken_branches()   540    541     def resume_continuing_branches(self):   542         self.get_namespace()._resume_continuing_branches()   543    544     def resume_abandoned_branches(self):   545         self.get_namespace()._resume_abandoned_branches()   546    547     def define_attribute_user(self, node):   548    549         """   550         Define 'node' as the user of attributes, indicating the point where the   551         user is defined.   552         """   553    554         self.get_namespace()._define_attribute_user(node)   555    556     def use_attribute(self, name, attrname, value=None):   557    558         """   559         Note usage on the attribute user 'name' of the attribute 'attrname',   560         noting an assignment if 'value' is specified.   561         """   562    563         return self.get_namespace()._use_attribute(name, attrname, value)   564    565     def use_specific_attribute(self, objname, attrname, from_name=None):   566    567         """   568         Note usage on the object having the given 'objname' of the attribute   569         'attrname'. If 'objname' is None, the current namespace is chosen as the   570         object providing the attribute.   571         """   572    573         return self.get_namespace()._use_specific_attribute(objname, attrname, from_name)   574    575     def define_attribute_accessor(self, name, attrname, node, value=None):   576    577         """   578         Note applicable attribute users providing the given 'name' when   579         accessing the given 'attrname' on the specified 'node', with the   580         optional 'value' indicating an assignment.    581         """   582    583         self.get_namespace()._define_attribute_accessor(name, attrname, node, value)   584    585     # Visitor methods.   586    587     def default(self, node, *args):   588         raise InspectError("Node class %r is not supported." % node.__class__)   589    590     def NOP(self, node):   591         for n in node.getChildNodes():   592             self.dispatch(n)   593    594     def NOP_ABANDON(self, node):   595         self.NOP(node)   596         self.abandon_branch()   597    598     def TEST_NOP(self, node):   599         self.use_name("__bool__", node)   600         self.NOP(node)   601    602     def OP(self, node):   603         for n in node.getChildNodes():   604             self.dispatch(n)   605         return make_instance()   606    607     def TEST_OP(self, node):   608         self.use_name("__bool__", node)   609         self.new_branchpoint()   610    611         # Propagate attribute usage to branches.   612         # Each node starts a new conditional region, effectively making a deeply   613         # nested collection of if-like statements.   614    615         for n in node.nodes:   616             self.new_branch(n)   617             self.dispatch(n)   618    619         # The nested regions must be terminated.   620    621         for n in node.nodes:   622             self.shelve_branch()   623    624         self.merge_branches()   625         return make_instance()   626    627     # Generic support for classes of operations.   628    629     def _ensureOperators(self, node):   630         attr, scope, namespace = self._get_with_scope("$operator")   631         if attr is None:   632             module = node._module   633             module.complete()   634             self["$operator"] = module   635         else:   636             module = attr.get_value()   637         return module   638    639     def _visitOperator(self, node, operator_name=None):   640    641         "Accounting method for the operator 'node'."   642    643         operator_module = self._ensureOperators(node)   644         operator_fn = operator_functions[operator_name or node.__class__.__name__]   645         self.use_specific_attribute(operator_module.full_name(), operator_fn)   646         return self.OP(node)   647    648     def _visitAttr(self, expr, attrname, node):   649    650         """   651         Process the attribute provided by the given 'expr' with the given   652         'attrname' and involving the given 'node'.   653         """   654    655         # Attempt to identify the nature of the attribute.   656    657         if isinstance(expr, Attr):   658             value = expr.get_value()   659    660             # Get the attribute and record its usage.   661             # NOTE: Need to provide concrete values for things like base classes   662             # NOTE: while also handling module attribute modification.   663    664             if isinstance(value, (Class, Module)):   665    666                 # Check for class.__class__.   667    668                 if attrname == "__class__" and isinstance(value, Class):   669                     attr = type_class   670                 else:   671                     attr = value.get(attrname) or make_instance()   672                 self.use_specific_attribute(value.full_name(), attrname)   673    674             elif isinstance(value, UnresolvedName):   675                 attr = UnresolvedName(attrname, value.full_name(), self)   676    677             # The actual attribute is not readily identifiable and is assumed   678             # to be an instance.   679    680             else:   681    682                 # Record any instance attributes.   683    684                 if expr.name == "self":   685                     self.store_instance_attr(attrname, tentative=True)   686    687                 attr = make_instance()   688    689                 # Note usage of the attribute where a local is involved.   690    691                 self._visitAttrUser(expr, attrname, node)   692    693         # No particular attribute has been identified, thus a general instance   694         # is assumed.   695    696         else:   697             attr = make_instance()   698             self.use_name(attrname, node)   699    700         return attr   701    702     def _visitAttrUser(self, expr, attrname, node, value=None):   703    704         """   705         Note usage of the attribute provided by 'expr' with the given 'attrname'   706         where a local is involved, annotating the given 'node'. If the optional   707         'value' is given, note an assignment for future effects on attributes   708         where such attributes are inferred from the usage.   709         """   710    711         # Access to attributes via a local in functions, classes or modules.   712         # Since module-level locals are globals that can be modified   713         # independently of the namespace, any attribute usage observations made   714         # here may be revoked later if such modification is thought to occur.   715    716         if expr.parent is self.get_namespace():   717             self.define_attribute_accessor(expr.name, attrname, node, value)   718         else:   719             self.use_name(attrname, node.expr, value, ns=expr.parent)   720    721     def _visitConst(self, value):   722    723         """   724         Register the constant given by 'value', if necessary, returning the   725         resulting object. The type name is noted as being used, thus preserving   726         the class in any generated program.   727         """   728    729         self.use_specific_attribute("__builtins__", self.importer.get_constant_type_name(value))   730         const = self.importer.make_constant(value)   731         self.use_constant(const)   732         return const   733    734     def _visitFunction(self, node, name):   735    736         """   737         Return a function object for the function defined by 'node' with the   738         given 'name'. If a lambda expression is being visited, 'name' should be   739         None.   740         """   741    742         # Define the function object.   743    744         function = Function(   745             name,   746             self.get_namespace(),   747             node.argnames,   748             node.defaults,   749             (node.flags & 4 != 0),   750             (node.flags & 8 != 0),   751             self.in_loop or self.in_function,   752             self,   753             node   754             )   755    756         self.add_object(function, any_scope=1)   757    758         # Make a back reference from the node for code generation.   759    760         node.unit = function   761    762         # Process the defaults.   763    764         for n in node.defaults:   765             self.expr = self.dispatch(n)   766             function.store_default(self.expr)   767    768         # Note attribute usage where tuple parameters are involved.   769    770         if function.tuple_parameters():   771             self.use_name("__getitem__", node)   772    773         # Record the namespace context of the function for later processing.   774    775         self.functions.append((node, self.namespaces + [function]))   776    777         # Store the function.   778    779         if name is not None:   780             self.store(name, function)   781         else:   782             self.store_lambda(function)   783    784         # Test the defaults and assess whether an dynamic object will result.   785    786         function.make_dynamic()   787         return function   788    789     def _visitFunctionBody(self, node, namespaces):   790    791         "Enter the function."   792    793         # Current namespace is the function.   794         # Previous namespace is the class.   795    796         if self.in_class(namespaces):   797             self.in_method = True   798    799         in_function = self.in_function   800         in_loop = self.in_loop   801         self.in_function = True   802         self.in_loop = False   803    804         self.namespaces = namespaces   805         self.dispatch(node.code)   806    807         self.in_loop = in_loop   808         self.in_function = in_function   809         self.in_method = False   810    811     # Specific handler methods.   812    813     visitAdd = _visitOperator   814    815     visitAnd = TEST_OP   816    817     visitAssert = NOP   818    819     def visitAssign(self, node):   820         self.expr = self.dispatch(node.expr)   821         self.in_assignment = True   822         for n in node.nodes:   823             self.dispatch(n)   824         self.in_assignment = False   825    826     def visitAssAttr(self, node):   827         expr = self.dispatch(node.expr)   828         attrname = node.attrname   829    830         # Record the attribute on the presumed target.   831    832         if isinstance(expr, Attr):   833             value = expr.get_value()   834    835             if expr.name == "self":   836                 self.store_instance_attr(attrname)   837                 self.use_attribute(expr.name, attrname, value)   838                 self._visitAttrUser(expr, attrname, node, self.expr)   839    840             elif isinstance(value, Module):   841                 self.store_module_attr(attrname, value)   842    843             elif isinstance(value, Class):   844                 self.store_class_attr(attrname, value)   845    846             # Note usage of the attribute where a local is involved.   847    848             else:   849                 self._visitAttrUser(expr, attrname, node, self.expr)   850    851         else:   852             self.use_name(attrname, node)   853    854     def visitAssList(self, node):   855    856         # Declare names which will be used by generated code.   857    858         self.use_name("__getitem__", node)   859    860         # Process the assignment.   861    862         for i, n in enumerate(node.nodes):   863             self.dispatch(n)   864             self._visitConst(i) # for __getitem__(i) at run-time   865    866     def visitAssName(self, node):   867         if hasattr(node, "flags") and node.flags == "OP_DELETE":   868             print >>sys.stderr, "Warning: deletion of attribute %r in %r is not supported." % (node.name, self.full_name())   869             #raise InspectError("Deletion of attribute %r is not supported." % node.name)   870    871         self.store(node.name, self.expr)   872         self.define_attribute_user(node)   873    874         # Ensure the presence of the given name in this namespace.   875         # NOTE: Consider not registering assignments involving methods, since   876         # NOTE: this is merely creating aliases for such methods.   877    878         if isinstance(self.get_namespace(), (Class, Module)):   879             if not isinstance(self.expr, Attr) or not isinstance(self.expr.get_value(), Function):   880                 self.use_specific_attribute(None, node.name)   881             else:   882                 fn = self.expr.get_value()   883                 ns = self.get_namespace().full_name()   884                 self.use_specific_attribute(fn.parent.full_name(), fn.name, "%s.%s" % (ns, node.name))   885    886     visitAssTuple = visitAssList   887    888     def visitAugAssign(self, node):   889    890         # Accounting.   891    892         operator_fn = operator_functions.get(node.op)   893         operator_module = self._ensureOperators(node)   894         self.use_specific_attribute(operator_module.full_name(), operator_fn)   895    896         # Process the assignment.   897    898         self.expr = self.dispatch(node.expr)   899    900         # NOTE: Similar to micropython.ast handler code.   901         # NOTE: Slices and subscripts are supported by __setitem__(slice) and   902         # NOTE: not __setslice__.   903    904         if isinstance(node.node, compiler.ast.Name):   905             self.visitAssName(node.node)   906         elif isinstance(node.node, compiler.ast.Getattr):   907             self.visitAssAttr(node.node)   908         else:   909             self.dispatch(node.node)   910             self.use_specific_attribute("__builtins__", "slice")   911             self.use_name("__setitem__", node)   912    913     visitBackquote = OP   914    915     visitBitand = _visitOperator   916    917     visitBitor = _visitOperator   918    919     visitBitxor = _visitOperator   920    921     def visitBreak(self, node):   922         self.NOP(node)   923         self.suspend_broken_branch()   924    925     visitCallFunc = OP   926    927     def visitClass(self, node):   928    929         """   930         Register the class at the given 'node' subject to the restrictions   931         mentioned in the module docstring.   932         """   933    934         if self.namespaces:   935             print >>sys.stderr, "Warning: class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name())   936             return   937         else:   938             if self.in_loop:   939                 print >>sys.stderr, "Warning: class %r in %r defined in a loop." % (node.name, self.full_name())   940    941             cls = get_class(node.name, self.get_namespace(), self, node)   942    943             # Make a back reference from the node for code generation.   944    945             node.unit = cls   946    947             # Process base classes in the context of the class's namespace.   948             # This confines references to such classes to the class instead of   949             # the namespace in which it is defined.   950    951             self.namespaces.append(cls)   952    953             # Visit the base class expressions, attempting to find concrete   954             # definitions of classes.   955    956             for base in node.bases:   957                 expr = self.dispatch(base)   958    959                 # Each base class must be constant and known at compile-time.   960    961                 if isinstance(expr, Attr):   962                     if expr.assignments != 1:   963                         raise InspectError("Base class %r for %r is not constant: %r" % (base, cls.full_name(), expr))   964                     elif not isinstance(expr.get_value(), Class):   965                         raise InspectError("Base class %r for %r is not a class: %r" % (base, cls.full_name(), expr.get_value()))   966                     else:   967                         cls.add_base(expr.get_value())   968    969                 # Where no expression value is available, the base class is   970                 # not identifiable.   971    972                 else:   973                     raise InspectError("Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name()))   974    975             # NOTE: Potentially dubious measure to permit __init__ availability.   976             # If no bases exist, adopt the 'object' class.   977    978             if not node.bases and not (self.name == "__builtins__" and node.name == "object"):   979                 expr = self.dispatch(compiler.ast.Name("object"))   980                 cls.add_base(expr.get_value())   981    982             # Make an entry for the class in the parent namespace.   983    984             self.namespaces.pop()   985             self.store(node.name, cls)   986             self.add_object(cls)   987    988             # Process the class body in its own namespace.   989             # Add __name__ to the namespace.   990    991             self.namespaces.append(cls)   992             self.store("__name__", self._visitConst(node.name))   993             self.dispatch(node.code)   994             self.namespaces.pop()   995    996             cls.finalise_attribute_usage()   997             return cls   998    999     def visitCompare(self, node):  1000   1001         # Accounting.  1002         # NOTE: Replicates some code in micropython.ast.visitCompare.  1003   1004         self.use_name("__bool__", node)  1005   1006         this_node = node  1007   1008         for op in node.ops:  1009             op_name, next_node = op  1010   1011             # Define name/attribute usage.  1012             # Get the applicable operation.  1013   1014             operator_fn = operator_functions.get(op_name)  1015   1016             # For operators, reference the specific function involved.  1017   1018             if operator_fn is not None:  1019                 operator_module = self._ensureOperators(node)  1020                 self.use_specific_attribute(operator_module.full_name(), operator_fn)  1021   1022             # Define __contains__ usage on the next node.  1023   1024             elif op_name.endswith("in"):  1025                 self.use_name("__contains__", next_node)  1026   1027             this_node = next_node  1028   1029         return self.OP(node)  1030   1031     def visitConst(self, node):  1032         return self._visitConst(node.value)  1033   1034     def visitContinue(self, node):  1035         self.NOP(node)  1036         self.suspend_continuing_branch()  1037   1038     visitDecorators = NOP  1039   1040     visitDict = OP  1041   1042     visitDiscard = NOP  1043   1044     visitDiv = _visitOperator  1045   1046     visitEllipsis = NOP  1047   1048     visitExec = NOP  1049   1050     visitExpression = OP  1051   1052     visitFloorDiv = _visitOperator  1053   1054     def visitFor(self, node):  1055         self.new_branchpoint(node)  1056   1057         # Declare names which will be used by generated code.  1058   1059         self.use_name("__iter__", node.list)  1060         self.use_name("next")  1061         self.use_name("StopIteration")  1062   1063         in_loop = self.in_loop  1064         self.in_loop = True  1065         self.dispatch(node.list)  1066   1067         # NOTE: Could generate AST nodes for the actual operations instead of  1068         # NOTE: manually generating code in micropython.ast.  1069   1070         self.expr = make_instance() # each element is a result of a function call  1071         self.dispatch(node.assign)  1072   1073         # Enter the loop.  1074         # Propagate attribute usage to branches.  1075   1076         self.new_branch(node)  1077         self.dispatch(node.body)  1078   1079         self.resume_continuing_branches()  1080   1081         self.shelve_branch()  1082   1083         self.in_loop = in_loop  1084   1085         # A null branch is used to record a path around the loop.  1086   1087         self.new_branch(node.else_ or NullBranch())  1088         self.shelve_branch()  1089   1090         self.merge_branches()  1091   1092         # The else clause is evaluated outside any branch.  1093   1094         if node.else_ is not None:  1095             self.dispatch(node.else_)  1096   1097         # Any suspended branches from the loop can now be resumed.  1098   1099         self.resume_broken_branches()  1100   1101     def visitFrom(self, node):  1102         module = self.complete_import(node.modname, True)  1103   1104         for name, alias in node.names:  1105   1106             # For specific names, obtain and store referenced objects using  1107             # the name or any alias provided in the current namespace.  1108   1109             if name != "*":  1110                 if module:  1111   1112                     # Missing names may refer to submodules.  1113   1114                     submodule = self.complete_import(node.modname + "." + name, True)  1115                     if submodule:  1116                         if not module.has_key(name):  1117                             module.store(name, submodule)  1118   1119                     # Complete the import if the name was found.  1120   1121                     if module.has_key(name):  1122                         attr = module[name]  1123                         self.store(alias or name, attr)  1124                         self.use_specific_attribute(module.full_name(), name)  1125                         continue  1126   1127                 # Support the import of names from missing modules.  1128   1129                 self.store(alias or name, UnresolvedName(name, node.modname, self))  1130   1131             # For wildcards, obtain and store all objects from a module in the  1132             # current namespace.  1133   1134             else:  1135                 if module:  1136                     for n in module.keys():  1137                         attr = module[n]  1138                         self.store(n, attr)  1139                         self.use_specific_attribute(module.full_name(), n)  1140   1141     def visitFunction(self, node):  1142         return self._visitFunction(node, node.name)  1143   1144     visitGenExpr = OP  1145   1146     visitGenExprFor = NOP  1147   1148     visitGenExprIf = NOP  1149   1150     visitGenExprInner = NOP  1151   1152     def visitGetattr(self, node):  1153         expr = self.dispatch(node.expr)  1154         attrname = node.attrname  1155         node._attr = self._visitAttr(expr, attrname, node)  1156         return node._attr  1157   1158     def visitGlobal(self, node):  1159         if self.namespaces:  1160             for name in node.names:  1161                 ns = self.namespaces[-1]  1162                 if not ns.make_global(name):  1163                     raise InspectError("Name %r is global and local in %r" % (name, ns.full_name()))  1164   1165                 # The name is recorded in an earlier process.  1166   1167     def visitIf(self, node):  1168         self.use_name("__bool__", node)  1169         self.new_branchpoint()  1170   1171         # Propagate attribute usage to branches.  1172   1173         for test, body in node.tests:  1174             self.dispatch(test)  1175   1176             self.new_branch(body)  1177             self.dispatch(body)  1178             self.shelve_branch()  1179   1180         # Maintain a branch for the else clause.  1181   1182         self.new_branch(node.else_ or NullBranch())  1183         if node.else_ is not None:  1184             self.dispatch(node.else_)  1185         self.shelve_branch()  1186   1187         self.merge_branches()  1188   1189     def visitIfExp(self, node):  1190         self.use_name("__bool__", node)  1191         self.new_branchpoint()  1192   1193         # Propagate attribute usage to branches.  1194   1195         self.dispatch(node.test)  1196   1197         self.new_branch(node.then)  1198         self.dispatch(node.then)  1199         self.shelve_branch()  1200   1201         self.new_branch(node.else_)  1202         self.dispatch(node.else_)  1203         self.shelve_branch()  1204   1205         self.merge_branches()  1206         return make_instance() # either outcome is possible  1207   1208     def visitImport(self, node):  1209         for name, alias in node.names:  1210             module = self.complete_import(name, alias)  1211             if alias is not None:  1212                 self.store(alias, module or UnresolvedName(None, name, self))  1213             else:  1214                 name_used = name.split(".")[0]  1215                 self.store(name_used, module or UnresolvedName(None, name_used, self))  1216   1217     visitInvert = _visitOperator  1218   1219     def visitKeyword(self, node):  1220         self.dispatch(node.expr)  1221         self._visitConst(node.name)  1222         self.keyword_names.add(node.name)  1223   1224     def visitLambda(self, node):  1225         fn = self._visitFunction(node, None)  1226         self.use_specific_attribute(None, fn.name)  1227         return fn  1228   1229     visitLeftShift = _visitOperator  1230   1231     def visitList(self, node):  1232         self.use_specific_attribute("__builtins__", "list")  1233         return self.OP(node)  1234   1235     def visitListComp(self, node):  1236   1237         # Note that explicit dispatch is performed.  1238   1239         if node.quals:  1240             self.visitListCompFor(node.quals[0], node.quals[1:], node.expr)  1241         return make_instance()  1242   1243     def visitListCompFor(self, node, following_quals, expr):  1244         self.new_branchpoint()  1245   1246         # Declare names which will be used by generated code.  1247   1248         self.use_name("__iter__", node.list)  1249         self.use_name("next")  1250   1251         in_loop = self.in_loop  1252         self.in_loop = True  1253         self.dispatch(node.list)  1254   1255         # NOTE: Could generate AST nodes for the actual operations instead of  1256         # NOTE: manually generating code in micropython.ast.  1257   1258         self.expr = make_instance() # each element is a result of a function call  1259         self.dispatch(node.assign)  1260   1261         # Enter the loop.  1262         # Propagate attribute usage to branches.  1263   1264         self.new_branch(node)  1265   1266         # Note that explicit dispatch is performed.  1267   1268         if node.ifs:  1269             self.visitListCompIf(node.ifs[0], node.ifs[1:], following_quals, expr)  1270         elif following_quals:  1271             self.visitListCompFor(following_quals[0], following_quals[1:], expr)  1272         else:  1273             self.dispatch(expr)  1274   1275         self.shelve_branch()  1276         self.in_loop = in_loop  1277   1278         self.merge_branches()  1279   1280     def visitListCompIf(self, node, following_ifs, following_quals, expr):  1281         self.use_name("__bool__", node)  1282         self.new_branchpoint()  1283   1284         # Propagate attribute usage to branches.  1285   1286         self.dispatch(node.test)  1287   1288         # Note that explicit dispatch is performed.  1289   1290         if following_ifs:  1291             self.visitListCompIf(following_ifs[0], following_ifs[1:], following_quals, expr)  1292         elif following_quals:  1293             self.visitListCompFor(following_quals[0], following_quals[1:], expr)  1294         else:  1295             self.new_branch(expr)  1296             self.dispatch(expr)  1297             self.shelve_branch()  1298   1299             # Maintain a branch for the else clause.  1300   1301             self.new_branch(NullBranch())  1302             self.shelve_branch()  1303   1304         self.merge_branches()  1305   1306     visitMod = _visitOperator  1307   1308     def visitModule(self, node):  1309   1310         # Make a back reference from the node for code generation.  1311   1312         node.unit = self  1313         return self.dispatch(node.node)  1314   1315     visitMul = _visitOperator  1316   1317     def visitName(self, node):  1318         attr = self.get_namespace().get_using_node(node.name, node) or make_instance()  1319         node._attr = attr  1320         return attr  1321   1322     def visitNot(self, node):  1323         self.use_name("__bool__", node)  1324         self.dispatch(node.expr)  1325         return make_instance()  1326   1327     visitOr = TEST_OP  1328   1329     visitPass = NOP  1330   1331     visitPower = _visitOperator  1332   1333     def _visitPrint(self, node, function_name):  1334         self.NOP(node)  1335         self.use_specific_attribute("__builtins__", function_name)  1336   1337     def visitPrint(self, node):  1338         self._visitPrint(node, "_print")  1339   1340     def visitPrintnl(self, node):  1341         self._visitPrint(node, "_printnl")  1342   1343     visitRaise = NOP_ABANDON  1344   1345     visitReturn = NOP_ABANDON  1346   1347     visitRightShift = _visitOperator  1348   1349     def visitSlice(self, node):  1350         return self._visitOperator(node, self.in_assignment and "AssSlice" or "Slice")  1351   1352     visitSliceobj = OP  1353   1354     def visitStmt(self, node):  1355         for n in node.nodes:  1356             self.dispatch(n)  1357   1358     visitSub = _visitOperator  1359   1360     def visitSubscript(self, node):  1361         return self._visitOperator(node, self.in_assignment and "AssSubscript" or "Subscript")  1362   1363     def visitTryExcept(self, node):  1364         self.new_branchpoint()  1365         self.dispatch(node.body)  1366   1367         for name, var, n in node.handlers:  1368             if name is not None:  1369                 self.dispatch(name)  1370   1371             self.new_branch(n)  1372   1373             # Any abandoned branches from the body can now be resumed.  1374   1375             self.resume_abandoned_branches()  1376   1377             # Establish the local for the handler.  1378   1379             if var is not None:  1380                 self.dispatch(var)  1381             if n is not None:  1382                 self.dispatch(n)  1383   1384             self.shelve_branch()  1385   1386         # The else clause maintains the usage from the body but without the  1387         # abandoned branches since they would never lead to the else clause  1388         # being executed.  1389   1390         self.new_branch(node.else_ or NullBranch())  1391         if node.else_ is not None:  1392             self.dispatch(node.else_)  1393         self.shelve_branch()  1394   1395         self.merge_branches()  1396   1397     visitTryFinally = NOP  1398   1399     visitTuple = OP  1400   1401     visitUnaryAdd = _visitOperator  1402   1403     visitUnarySub = _visitOperator  1404   1405     def visitWhile(self, node):  1406         self.use_name("__bool__", node)  1407         self.new_branchpoint(node)  1408   1409         # Propagate attribute usage to branches.  1410   1411         in_loop = self.in_loop  1412         self.in_loop = True  1413   1414         # The test is evaluated initially and again in the loop.  1415   1416         self.dispatch(node.test)  1417   1418         self.new_branch(node)  1419         self.dispatch(node.body)  1420   1421         self.resume_continuing_branches()  1422   1423         self.dispatch(node.test)  1424         self.shelve_branch()  1425   1426         self.in_loop = in_loop  1427   1428         # A null branch is used to record a path around the loop.  1429   1430         self.new_branch(node.else_ or NullBranch())  1431         self.shelve_branch()  1432   1433         self.merge_branches()  1434   1435         # The else clause is evaluated outside any branch.  1436   1437         if node.else_ is not None:  1438             self.dispatch(node.else_)  1439   1440         # Any suspended branches from the loop can now be resumed.  1441   1442         self.resume_broken_branches()  1443   1444     visitWith = NOP  1445   1446     visitYield = NOP  1447   1448 # vim: tabstop=4 expandtab shiftwidth=4