micropython

micropython/inspect.py

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