micropython

micropython/trans.py

464:04c6f309c52f
2011-09-05 Paul Boddie Attempted to introduce optimisations to avoid temporary storage allocation and to defer the production of instructions that save values in temporary storage. Changed the assignment handling to attempt to make use of "live" working values. Changed the default target of various instructions and simplified the testing of instructions that affect the working value. Added default source and working register values for instructions. Removed the redundant load_result parameter for _endCallFunc.
     1 #!/usr/bin/env python     2      3 """     4 Translate the AST of a Python program into a more interpretable representation.     5      6 Copyright (C) 2007, 2008, 2009, 2010, 2011 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 from micropython.common import *    23 from micropython.data import *    24 from micropython.rsvp import *    25 import compiler.ast    26     27 class Helper:    28     29     "Internal helper methods for AST visitors."    30     31     # Allocation-related methods.    32     33     def make_instance(self, cls, n):    34     35         """    36         Request a new instance using the given class 'cls' and with 'n'    37         attributes.    38         """    39     40         # Load the class in order to locate the instance template.    41     42         self.new_op(LoadConst(cls))    43     44         # NOTE: Instance headers are one location.    45     46         self.new_op(MakeInstance(n + 1))    47     48     def make_exception(self, name):    49     50         "Make an exception of the given 'name' using 'node'."    51     52         # NOTE: Reserving an attribute.    53     54         self.make_instance(self.get_builtin_class(name), 1)    55     56     # Name-related methods.    57     58     def get_scope(self, name):    59     60         "Return the scope for the given 'name'."    61     62         attr, scope, from_name = self.unit._get_with_scope(name)    63         return scope    64     65     def load_builtin(self, name, node):    66     67         "Generate an instruction loading 'name' for the given 'node'."    68     69         self.new_op(LoadAddress(self.get_builtin(name)))    70     71     def get_builtin_class(self, name):    72     73         "Return the built-in class with the given 'name'."    74     75         return self.get_builtin(name).get_value()    76     77     def get_builtin(self, name):    78     79         "Return the built-in module definition for the given 'name'."    80     81         if self.builtins is not None:    82             try:    83                 return self.builtins[name]    84             except KeyError:    85                 raise TranslateError("No __builtins__ definition is available for name %r." % name)    86         else:    87             raise TranslateError("No __builtins__ module is available for name %r." % name)    88     89     # Common methods.    90     91     def _generateGuards(self, node):    92     93         if not (self.optimiser.should_optimise_accesses_by_attribute_usage() and hasattr(node, "_attrtypes")):    94             return    95     96         # For each name, attempt to restrict the type employed.    97     98         for name, targets in node._attrtypes.items():    99    100             # NOTE: Need to merge targets using the same type but suggesting   101             # NOTE: different kinds of attributes (instance vs. class).   102    103             # Where only one object type is suggested, produce a guard.   104             # NOTE: This only supports classes as types, not modules.   105    106             if len(targets) == 1:   107                 target_name, is_static = list(targets)[0]   108    109                 # Access the object table to get the attribute.   110                 # NOTE: This depends on the special entry in the table   111                 # NOTE: for class equivalence tests.   112    113                 try:   114                     obj = self.objtable.access(target_name, target_name)   115    116                 # Where no attribute entry exists, the target could be a module.   117                 # NOTE: Should perhaps raise an error.   118    119                 except TableError, exc:   120                     print "Possible guard for", target_name, "not enforceable."   121                     continue   122    123                 # NOTE: Could test the correctness of the guard where the nature   124                 # NOTE: of the name is known.   125                 # NOTE: The known value would be retrieved from the unit's   126                 # NOTE: locals and tested as being a class or an instance of a   127                 # NOTE: particular class.   128    129                 # Generate the guard by loading a reference to the class.   130    131                 after_test_block = self.new_block()   132    133                 self.new_op(LoadClass(obj, target="source"))   134    135                 # For only static attributes, classes are acceptable.   136    137                 if is_static:   138    139                     # Generate name is target (for classes).   140    141                     self.dispatch(compiler.ast.Name(name))   142                     self.new_op(TestIdentity(source="source", target="status"))   143    144                     # Jump to the next guard or the code if successful.   145    146                     self.new_op(JumpIfTrue(after_test_block, working="status"))   147    148                 # Where instance attributes are involved, only instances are   149                 # acceptable.   150    151                 # Generate isinstance(name, target).   152    153                 self.dispatch(compiler.ast.Name(name))   154                 self.new_op(CheckInstance(source="source", target="status"))   155    156                 # Jump to the next guard or the code if successful.   157    158                 self.new_op(JumpIfTrue(after_test_block, working="status"))   159    160                 # Where the type is inappropriate, raise an exception.   161    162                 self.make_exception("TypeError")   163                 self.set_target("exception")   164                 self.new_op(RaiseException())   165    166                 self.set_block(after_test_block)   167    168     def _visitAttr(self, node, classes):   169    170         """   171         Visit the attribute-related 'node', generating instructions based on the   172         given 'classes'.   173         """   174    175         self.dispatch(node.expr)   176         self._generateAttr(node, node.attrname, classes)   177    178     def _generateAttr(self, node, attrname, classes):   179    180         """   181         Generate code for the access to 'attrname' using the given 'classes'.   182         """   183    184         AddressInstruction, AddressContextInstruction, AddressContextCondInstruction, \   185             AttrInstruction, AttrIndexInstruction, AttrIndexContextCondInstruction = classes   186    187         # Where the last operation (defining the attribute owner) yields a   188         # constant...   189    190         target_plus_name = self.optimiser.optimise_constant_accessor()   191    192         # Only try and discover the position if the target can be resolved.   193         # Since instances cannot be constants, this involves classes and   194         # modules.   195         # It is acceptable to replace the instruction providing the constant   196         # input because doing so does not lose any input information required by   197         # the replacement instructions.   198    199         if target_plus_name is not None:   200             target, target_name = target_plus_name   201    202             # Check for class.__class__.   203    204             if attrname == "__class__":   205                 if isinstance(target, Class):   206                     if AddressInstruction is LoadAddress:   207                         self.replace_active_value(LoadAddress(self.get_builtin("type")))   208                         return   209                     else:   210                         raise TranslateError("Assigning to __class__ is not permitted.")   211    212             # Access the object table to get the attribute.   213    214             try:   215                 attr = self.objtable.access(target_name, attrname)   216             except TableError, exc:   217                 raise TranslateError(exc.args[0])   218    219             # Produce a suitable instruction.   220    221             if AddressInstruction is not None:   222                 self.replace_active_value(AddressInstruction(attr))   223             else:   224                 raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname)   225    226             return   227    228         # Where the last operation involves the special 'self' name, check to   229         # see if the attribute is acceptably positioned and produce a direct   230         # access to the attribute.   231    232         # This is the only reliable way of detecting instance accesses at   233         # compile-time since in general, objects could be classes or modules,   234         # but 'self' should only refer to instances.   235    236         elif self.optimiser.optimise_self_access(self.unit, attrname):   237    238             # Either generate an instruction operating on an instance attribute.   239    240             try:   241                 attr = self.unit.parent.instance_attributes()[attrname]   242                 self.new_op(AttrInstruction(attr))   243                 return   244    245             # Or generate an instruction operating on a class attribute.   246             # NOTE: Any simple instruction providing self is not removed.   247    248             except KeyError:   249    250                 try:   251                     attr = self.unit.parent.all_attributes()[attrname]   252    253                     # Switch the context if the class attribute is compatible with   254                     # the instance.   255    256                     if attr.defined_within_hierarchy():   257    258                         # Only permit loading (not storing) of class attributes via self.   259    260                         if AddressContextInstruction is not None:   261                             self.new_op(AddressContextInstruction(attr))   262                         else:   263                             raise TranslateError("Storing of class attribute %r via self not permitted." % attrname)   264    265                     # Preserve the context if the class attribute comes from an   266                     # incompatible class.   267    268                     elif attr.defined_outside_hierarchy():   269    270                         # Only permit loading (not storing) of class attributes via self.   271    272                         if AddressInstruction is not None:   273                             self.new_op(AddressInstruction(attr))   274                         else:   275                             raise TranslateError("Storing of class attribute %r via self not permitted." % attrname)   276    277                     # Otherwise, test for a suitable context at run-time.   278    279                     else:   280    281                         # Only permit loading (not storing) of class attributes via self.   282    283                         if AddressContextCondInstruction is not None:   284                             self.new_op(AddressContextCondInstruction(attr))   285                         else:   286                             raise TranslateError("Storing of class attribute %r via self not permitted." % attrname)   287    288                     return   289    290                 # Or delegate the attribute access to a general instruction   291                 # since the kind of attribute cannot be deduced.   292    293                 except KeyError:   294                     pass   295    296         # Attempt to deduce the target of an attribute access by searching for a   297         # unique type providing the names associated with the accessed object.   298    299         elif self.optimiser.should_optimise_accesses_by_attribute_usage():   300    301             target_names = self.possible_accessor_types(node)   302    303             if target_names is not None and len(target_names) == 1:   304                 target_name, is_static = list(target_names)[0]   305    306                 # Check for class.__class__.   307    308                 if attrname == "__class__":   309                     if is_static:   310                         self.load_builtin("type", node)   311                         return   312    313                 # Access the object table to get the attribute.   314    315                 try:   316                     attr = self.objtable.access(target_name, attrname)   317    318                 # Disallow non-class/instance optimisations.   319    320                 except TableError, exc:   321                     print "Possible optimisation for", target_name, "not permissable."   322    323                 # Produce a suitable instruction.   324    325                 else:   326                     if AddressContextCondInstruction is not None and attr.is_static_attribute():   327                         self.new_op(AddressContextCondInstruction(attr))   328                     elif AttrInstruction is not None and not attr.is_static_attribute():   329                         self.new_op(AttrInstruction(attr))   330                     else:   331                         raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname)   332    333                     return   334    335         # Check for class.__class__.   336    337         if attrname == "__class__":   338    339             # Remember the accessor.   340    341             temp_accessor = self.get_temp()   342    343             attr_block = self.new_block()   344             end_block = self.new_block()   345    346             self.new_op(CheckClass(target="status"))   347             self.new_op(JumpIfFalse(attr_block, working="status"))   348             self.load_builtin("type", node)   349             self.new_op(Jump(end_block))   350             self.set_block(attr_block)   351    352             # Recall the accessor.   353    354             self.new_op(temp_accessor)   355    356         # Otherwise, perform a normal operation.   357    358         try:   359             index = self.objtable.get_index(attrname)   360    361         except self.objtable.TableError:   362    363             # If this error arises on generated code, check the names_used   364             # attribute on the Importer.   365    366             raise TranslateError("No attribute entry exists for name %r." % attrname)   367    368         # NOTE: Test for class vs. instance attributes, generating   369         # NOTE: context-related instructions.   370    371         if AttrIndexContextCondInstruction is not None:   372             self.new_op(AttrIndexContextCondInstruction(index))   373    374         # Store instructions do not need to consider context modifications.   375    376         else:   377             self.new_op(AttrIndexInstruction(index))   378    379         # Where __class__ was involved, define the start of the following code.   380    381         if attrname == "__class__":   382             self.set_block(end_block)   383             self.discard_temp(temp_accessor)   384    385     # Invocations involve the following:   386     #   387     # 1. Reservation of a frame for the arguments   388     # 2. Identification of the target which is then held in temporary storage   389     # 3. Optional inclusion of a context (important for methods)   390     # 4. Preparation of the argument frame   391     # 5. Invocation of the target   392     # 6. Discarding of the frame   393     #   394     # In order to support nested invocations - such as a(b(c)) - use of the   395     # temporary storage is essential.   396    397     def _startCallFunc(self):   398    399         "Record the location of the invocation."   400    401         op = MakeFrame()   402         self.new_op(op) # records the start of the frame   403         self.frame_makers.append(op)   404    405     def _generateCallFunc(self, args, node):   406    407         """   408         Support a generic function invocation using the given 'args', occurring   409         on the given 'node', where the expression providing the invocation   410         target has just been generated.   411    412         In other situations, the invocation is much simpler and does not need to   413         handle the full flexibility of a typical Python invocation. Internal   414         invocations, such as those employed by operators and certain   415         control-flow mechanisms, use predetermined arguments and arguably do not   416         need to support the same things as the more general invocations.   417         """   418    419         target, context, temp_target, temp_context = self._generateCallFuncContext()   420         self._generateCallFuncArgs(target, context, temp_target, temp_context, args, node)   421         return temp_target, target, temp_context   422    423     def _generateCallFuncContext(self):   424    425         """   426         Produce code which loads and checks the context of the current   427         invocation, the instructions for whose target have already been   428         produced, returning a list of instructions which reference the   429         invocation target.   430         """   431    432         t = self.optimiser.optimise_known_target()   433         if t:   434             target, context = t   435    436             # Detect dynamic functions acting like instances.   437    438             if isinstance(target, Function) and target.is_dynamic():   439                 target, context = None, None   440         else:   441             target, context = None, None   442    443         # Store the target in temporary storage for subsequent referencing.   444    445         temp_target = self.optimiser.optimise_temp_storage()   446    447         # Where a target or context are not known or where an instance is known   448         # to be the context, load the context.   449    450         if target is None or isinstance(context, Instance):   451             self.new_op(temp_target)   452             self.new_op(Transfer(source="working_context", target="working"))   453             temp_context = self.optimiser.optimise_temp_storage()   454             self.new_op(StoreFrame(0))   455    456         # Class contexts should be made available for testing of the first   457         # argument.   458         # NOTE: Class methods should eventually be supported.   459    460         elif isinstance(context, Class):   461             self.new_op(temp_target)   462             self.new_op(Transfer(source="working_context", target="working"))   463             temp_context = self.optimiser.optimise_temp_storage()   464    465         # Otherwise omit the context.   466    467         else:   468             temp_context = None   469    470         return target, context, temp_target, temp_context   471    472     def _generateCallFuncArgs(self, target, context, temp_target, temp_context, args, node):   473    474         """   475         Given invocation 'target' and 'context' information, the 'temp_target'   476         reference to the target, the 'temp_context' reference to the context, a   477         list of nodes representing the 'args' (arguments), generate instructions   478         which load the arguments for the invocation defined by the given 'node'.   479         """   480    481         # Evaluate the arguments.   482    483         employed_positions = set()   484         employed_keywords = set()   485         extra_keywords = []   486         positional_args = []   487         keyword_args = []   488    489         # Find keyword arguments in advance in order to help resolve targets.   490    491         have_keywords = 0   492    493         for arg in args:   494             if isinstance(arg, compiler.ast.Keyword):   495                 employed_keywords.add(arg.name)   496                 keyword_args.append(arg)   497                 have_keywords = 1   498             elif not have_keywords:   499                 positional_args.append(arg)   500    501         possible_targets = self.paramtable.all_possible_objects(employed_keywords)   502    503         # Note the presence of the context in the frame where appropriate.   504    505         # For unknown invocations and method invocations.   506    507         if target is None or isinstance(context, Instance):   508             ncontext = 1   509             expect_testable_self = 0   510    511         # Handle calls to classes by obtaining the instantiator function.   512         # A context is reserved for the new instance, but this is not provided   513         # in the invocation (since the instantiator will fill the locals slot   514         # concerned).   515    516         elif isinstance(target, Class):   517             ncontext = 1   518             expect_testable_self = 0   519             target = target.get_instantiator()   520    521         # Method calls via classes.   522    523         elif isinstance(context, Class):   524             ncontext = 0   525             expect_testable_self = 1   526    527         # Function calls.   528    529         else:   530             ncontext = 0   531             expect_testable_self = 0   532    533         # Traverse the positional arguments adding them using the incrementing   534         # frame position.   535    536         first = 1   537         frame_pos = ncontext   538         temp_first_argument = None   539    540         for arg in positional_args:   541             self.dispatch(arg)   542             self.new_op(StoreFrame(frame_pos))   543             employed_positions.add(frame_pos)   544    545             # Check to see if the first argument is appropriate (compatible with   546             # the target where methods are being invoked via classes).   547    548             if first and (expect_testable_self or target is None):   549    550                 # Drop any test if the target and the context are known.   551    552                 if not self.optimiser.have_correct_self_for_target(context, self.unit):   553    554                     # Otherwise, remember the first argument for a subsequent   555                     # test.   556    557                     temp_first_argument = self.optimiser.optimise_temp_storage()   558    559             first = 0   560             frame_pos += 1   561    562         # Adjust the invocation frame for unknown invocations.   563         # Test the first argument if appropriate.   564    565         self._generateCallFuncContextTest(target, temp_context, temp_first_argument, node)   566    567         # Traverse the keyword arguments adding them at the appropriate frame   568         # positions.   569    570         max_keyword_pos = -1   571    572         for arg in keyword_args:   573    574             # Optimise where the target is known now.   575    576             if target is not None:   577    578                 # Find the parameter table entry for the target.   579    580                 target_name = target.full_name()   581    582                 # Look for a callable with the precise target name.   583    584                 table_entry = self.paramtable.table[target_name]   585    586                 # Look the name up in the parameter table entry.   587    588                 try:   589                     pos = table_entry[arg.name]   590    591                 # Where no position is found, this could be an extra keyword   592                 # argument.   593    594                 except KeyError:   595                     extra_keywords.append(arg)   596                     continue   597    598                 # Test for illegal conditions.   599    600                 if pos in employed_positions:   601                     raise TranslateError("Keyword argument %r overwrites parameter %r." % (arg.name, pos))   602    603                 employed_positions.add(pos)   604    605                 # Generate code for the keyword and the positioning   606                 # operation.   607    608                 self.dispatch(arg.expr)   609                 self.new_op(StoreFrame(pos))   610    611             # Otherwise, generate the code needed to obtain the details of   612             # the parameter location.   613    614             else:   615    616                 # Combine the target details with the name to get the location.   617                 # See the access method on the List class.   618    619                 try:   620                     paramindex = self.paramtable.get_index(arg.name)   621    622                 # Where no position is found, this could be an extra keyword   623                 # argument.   624    625                 except self.paramtable.TableError:   626                     extra_keywords.append(arg)   627                     continue   628    629                 # Generate code for the keyword and the positioning   630                 # operation. Get the value as the source of the assignment.   631    632                 self.dispatch(arg.expr)   633                 self.record_value()   634    635                 # Store the source value using the callable's parameter   636                 # table information.   637    638                 self.new_op(temp_target)   639                 self.new_op(StoreFrameIndex(paramindex))   640    641                 self.assign_value()   642                 self.discard_value()   643    644                 # Record the highest possible frame position for this argument.   645    646                 max_keyword_pos = max(max_keyword_pos, max(self.paramtable.all_attribute_positions(arg.name)))   647    648             # Use the frame position counter as a general argument counter.   649    650             frame_pos += 1   651    652         # NOTE: Extra keywords are not supported.   653         # NOTE: Somehow, the above needs to be combined with * arguments.   654    655         if extra_keywords:   656             print "Warning: extra keyword argument(s) %s not handled." % ", ".join([arg.name for arg in extra_keywords])   657    658         # Either test for a complete set of arguments.   659    660         if target is not None:   661    662             # Make sure that enough arguments have been given.   663    664             nargs_max = len(target.positional_names)   665             ndefaults = len(target.defaults)   666             nargs_min = nargs_max - ndefaults   667    668             # Visit each argument position and look for a supplied argument.   669    670             for i in range(ncontext, nargs_min):   671                 if i not in employed_positions:   672                     raise TranslateError(   673                         "Argument %r not supplied for %r: need at least %d argument(s)." % (i+1, target.name, nargs_min))   674    675             nargs = frame_pos   676    677             # Determine whether too many arguments have been given and how big   678             # the frame should be.   679    680             # For parameter lists with * or ** parameters, accept as many   681             # arguments as are allowed or as many as we have.   682    683             if target.has_star or target.has_dstar:   684                 frame_size = max(nargs, nargs_max)   685    686                 # NOTE: We now need to pack these arguments into a suitable   687                 # NOTE: structure for the * parameter.   688    689             # For other parameter lists, only accept as many arguments as we are   690             # allowed.   691    692             elif nargs > nargs_max:   693                 raise TranslateError(   694                     "Too many arguments for %r: need at most %d argument(s)." % (target.name, nargs_max))   695    696             else:   697                 frame_size = nargs_max   698    699             # Where defaults are involved, put them into the frame.   700    701             self._generateCallFuncDefaultArgs(target, temp_target, nargs_min, nargs_max, employed_positions)   702    703             # Set the frame size.   704    705             self._endCallFuncArgs(frame_size)   706    707         # Or just set the frame size and have the function check the arguments.   708    709         else:   710             max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1)   711             self._endCallFuncArgs(max_pos + 1)   712    713     def _generateCallFuncDefaultArgs(self, target, temp_target, nargs_min, nargs_max, employed_positions):   714    715         """   716         For the given 'target' and 'temp_target' reference to the target,   717         generate default arguments for those positions in the range   718         'nargs_min'...'nargs_max' which are not present in the   719         'employed_positions' collection.   720         """   721    722         # Where appropriate, construct a dynamic object to hold the defaults.   723    724         dynamic = target.is_dynamic()   725    726         # Here, we use negative index values to visit the right hand end of   727         # the defaults list.   728    729         for pos in range(nargs_min, nargs_max):   730             if pos not in employed_positions:   731                 if dynamic:   732                     self.new_op(temp_target)   733                     self.new_op(LoadAttr(target.default_attrs[pos - nargs_min]))   734                 else:   735                     self.new_op(LoadAddress(target.default_attrs[pos - nargs_min]))   736                 self.new_op(StoreFrame(pos))   737    738     def _generateCallFuncContextTest(self, target, temp_context, temp_first_argument, node):   739    740         """   741         Generate code involved in a call to the given 'target' to test the   742         context provided by 'temp_context' against 'temp_first_argument', and to   743         signal an exception (using 'node') if the context is incompatible with   744         the first frame argument.   745    746         In addition, the invocation frame will be shifted if 'temp_context'   747         indicates a function or a class.   748         """   749    750         adjust_block = self.new_block()   751         continue_block = self.new_block()   752    753         # Add some preliminary tests where the target is not known.   754    755         if target is None:   756    757             # Adjust the frame if a replaceable context is provided.   758    759             self.new_op(temp_context)   760             self.new_op(CheckContext(target="status"))   761             self.new_op(JumpIfFalse(adjust_block, working="status"))   762    763             # Skip adjustment and tests if the context is not a class.   764             # Classes themselves employ a placeholder context so that   765             # instantiators can be callable with a context which will be   766             # overwritten in the frame.   767    768             # Here, the working value should still refer to the context.   769    770             self.new_op(CheckClass(target="status"))   771             self.new_op(JumpIfFalse(continue_block, working="status"))   772    773         # Test any explicit first argument against the context.   774    775         if temp_first_argument is not None:   776    777             # Check the current value (the argument) against the known context   778             # (given as the source).   779    780             if self.new_op(temp_context.copy()):   781                 self.last_op().target = "source"   782                 self.update_temp(temp_context, self.last_op())   783    784             self.new_op(temp_first_argument)   785             self.new_op(CheckInstance(source="source", target="status"))   786    787             if target is None:   788                 self.new_op(JumpIfTrue(adjust_block, working="status"))   789             else:   790                 self.new_op(JumpIfTrue(continue_block, working="status"))   791    792             # Where the context is inappropriate, drop the incomplete frame and   793             # raise an exception.   794    795             self.new_op(DropFrame())   796    797             self.make_exception("TypeError")   798             self.set_target("exception")   799             self.new_op(RaiseException())   800    801         if target is None or temp_first_argument is not None:   802             self.set_block(adjust_block)   803             self.new_op(AdjustFrame(1))   804    805             self.set_block(continue_block)   806    807     def _doCallFunc(self, temp_target, target=None):   808    809         "Make the invocation."   810    811         # For classes, the target itself is used, since the instantiator will be   812         # obtained via the class.   813    814         if isinstance(target, (Class, Function)):   815             self.new_op(JumpWithFrameDirect(target, working="status"))   816         else:   817             self.new_op(temp_target)   818             self.new_op(LoadCallable())   819             self.new_op(JumpWithFrame())   820    821     def _endCallFuncArgs(self, nargs):   822    823         "Set the frame size."   824    825         self.frame_makers[-1].attr = nargs   826         self.frame_makers.pop()   827    828     def _endCallFunc(self, temp_target=None, temp_context=None):   829    830         "Finish the invocation and tidy up afterwards."   831    832         self.new_op(DropFrame())   833    834         # Discard any temporary storage instructions.   835    836         if temp_target is not None:   837             self.discard_temp(temp_target)   838    839         if temp_context is not None:   840             self.discard_temp(temp_context)   841    842     def _visitFunctionDeclaration(self, node):   843    844         """   845         Visit the function declaration at 'node', which can be a lambda or a   846         named function. As a consequence an instruction will be generated which   847         provides a reference to the function.   848         """   849    850         fn = node.unit   851         ndefaults = len(fn.defaults)   852         temp = self._generateFunctionDefaults(fn)   853    854         # Populate the new object required for the function.   855    856         if temp is not None:   857             self.new_op(LoadConst(fn))   858             self.new_op(LoadCallable(target="source"))   859             self.new_op(temp)   860             self.new_op(StoreCallable(source="source"))   861             self.new_op(temp)   862             #self.discard_temp(temp)   863         else:   864             self.new_op(LoadFunction(fn))   865    866     def _visitFunctionDefinition(self, node):   867    868         """   869         Visit the function definition at 'node', which can be a lambda or a   870         named function, generating the prelude with argument and default   871         checking, plus the body of the function itself.   872         """   873    874         # Check frames using the function's details.   875    876         fn = node.unit   877         nparams = len(fn.positional_names)   878         ndefaults = len(fn.defaults)   879    880         fn.body_block = self.new_block()   881    882         # Check the number of parameters and defaults.   883    884         self.new_op(CheckFrame((nparams, ndefaults), target="status"))   885    886         if ndefaults > 0:   887             if fn.is_dynamic():   888                 self.new_op(LoadTemp(0)) # context provides storage   889             else:   890                 self.new_op(LoadFunction(fn))   891    892             self.new_op(FillDefaults((nparams, ndefaults)))   893    894         # Produce the body.   895    896         self.set_block(fn.body_block)   897    898         # For functions with star parameters, make a special list for the   899         # extra arguments and re-map the parameter.   900    901         if fn.has_star:   902             self.new_op(CopyExtra(nparams))   903    904             # Ensure that the star parameter has a slot in the frame.   905    906             self.new_op(CheckExtra(nparams, target="status"))   907             self.new_op(StoreTemp(nparams))   908    909         # Extend the frame for local usage.   910    911         extend = ExtendFrame()   912         self.new_op(extend)   913    914         # Perform tuple assignment for any tuple parameters.   915    916         self._visitFunctionTupleParameters(fn, node)   917    918         # Add any attribute usage guards.   919    920         self._generateGuards(node)   921    922         # Visit the actual code.   923    924         self.dispatch(node.code)   925    926         # Add a return statement where one is not already produced.   927    928         if not isinstance(self.last_op(), Return):   929    930             # Return None for normal functions without explicit return   931             # statements.   932    933             if not fn.is_lambda():   934                 self.dispatch(compiler.ast.Name("None"))   935    936             self.new_op(Return())   937    938         # Make sure that enough frame space is reserved from the start.   939    940         self.set_frame_usage(node, extend)   941    942     def _visitFunctionTupleParameters(self, fn, node, parameters=None):   943    944         """   945         Visit the tuple parameters for function 'fn', obtaining the appropriate   946         elements from each supplied argument and assigning them to the specified   947         names for each parameter.   948         """   949    950         if parameters is not None:   951             self._generateAttr(node, "__getitem__", self.attribute_load_instructions)   952             temp_getitem = self.optimiser.optimise_temp_storage()   953    954         for i, parameter in parameters or fn.tuple_parameters():   955    956             # Either load the parameter from the frame.   957    958             if parameters is None:   959                 self.new_op(LoadName(Attr(i, None, None)))   960    961             # Or load a value from the current collection.   962    963             else:   964                 self._startCallFunc()   965                 self.new_op(temp_getitem)   966                 temp_target, target, temp_context = self._generateCallFunc([compiler.ast.Const(i)], node)   967                 self._doCallFunc(temp_target, target)   968                 self._endCallFunc()   969    970             # Where a tuple is the target, attempt to descend into the value   971             # obtained.   972    973             if isinstance(parameter, list):   974                 self._visitFunctionTupleParameters(fn, node, parameter)   975    976             # Store the item in the namespace entry for the given name.   977    978             else:   979                 self.record_value()   980                 self.new_op(StoreName(fn[parameter]))   981                 self.assign_value()   982                 self.discard_value()   983    984         if parameters is not None:   985             self.discard_temp(temp_getitem)   986    987     def _generateFunctionDefaults(self, function):   988    989         """   990         Generate the default initialisation code for 'function', returning   991         a temporary storage reference if a dynamic object was created for the   992         function.   993         """   994    995         attr_to_default = zip(function.default_attrs, function.defaults)   996         if not attr_to_default:   997             return None   998    999         # Where non-constant defaults are involved, construct a dynamic object  1000         # to hold the defaults.  1001   1002         dynamic = function.is_dynamic()  1003   1004         if dynamic:  1005             self.make_instance(self.get_builtin_class("function"), len(attr_to_default))  1006             temp = self.get_temp()  1007   1008         for attr, default in attr_to_default:  1009             self.dispatch(default)  1010   1011             self.record_value()  1012             if dynamic:  1013                 self.new_op(temp)  1014                 self.new_op(StoreAttr(attr))  1015             else:  1016                 self.new_op(StoreAddress(attr))  1017             self.assign_value()  1018             self.discard_value()  1019   1020         if dynamic:  1021             return temp  1022         else:  1023             return None  1024   1025     def _visitName(self, node, classes):  1026   1027         """  1028         Visit the name-related 'node', generating instructions based on the  1029         given 'classes'.  1030         """  1031   1032         name = node.name  1033   1034         # Get the expected scope of the name.  1035   1036         scope = getattr(node, "_scope", None) or self.get_scope(name)  1037         self._generateName(name, scope, classes, node)  1038   1039     def _generateName(self, name, scope, classes, node):  1040   1041         """  1042         Generate code for the access to 'name' in 'scope' using the given  1043         'classes', and using the given 'node' as the source of the access.  1044         """  1045   1046         NameInstruction, AddressInstruction, AddressContextInstruction = classes  1047   1048         # Handle names referring to constants.  1049   1050         if scope == "constant":  1051             const = self.importer.get_predefined_constant(name)  1052             self.new_op(LoadConst(const))  1053   1054         # Handle all other names.  1055   1056         elif scope == "local":  1057             unit = self.unit  1058             if isinstance(unit, Function):  1059                 self.new_op(NameInstruction(unit.all_locals()[name]))  1060             elif isinstance(unit, Class):  1061                 if AddressContextInstruction is not None:  1062                     self.new_op(LoadConst(unit))  1063                     self.new_op(AddressContextInstruction(unit.all_class_attributes()[name]))  1064                 else:  1065                     self.new_op(AddressInstruction(unit.all_class_attributes()[name]))  1066             elif isinstance(unit, Module):  1067                 self.new_op(AddressInstruction(unit.module_attributes()[name]))  1068             else:  1069                 raise TranslateError("Program unit has no local %r." % name)  1070   1071         elif scope == "global":  1072             globals = self.module.module_attributes()  1073             if globals.has_key(name):  1074                 self.new_op(AddressInstruction(globals[name]))  1075             else:  1076                 raise TranslateError("Module has no attribute %r." % name)  1077   1078         elif scope == "builtins":  1079             self.new_op(AddressInstruction(self.get_builtin(name)))  1080   1081         else:  1082             # NOTE: This may happen because a class attribute is optimised away.  1083             print "Program unit uses unknown name %r." % name  1084   1085     def _visitUnary(self, node):  1086   1087         """  1088         Invoke the appropriate operator module function for the operation  1089         represented by 'node'.  1090         """  1091   1092         temp_fn = self._getOperatorFunction(node)  1093         self._visitCall(node, temp_fn, (node.expr,))  1094         self.discard_temp(temp_fn)  1095   1096     def _visitBinaryBit(self, node):  1097   1098         """  1099         Need to impose binary rules over a sequence of nodes. The  1100         short-circuiting of the similar logical operators is not imposed by the  1101         bitwise operators.  1102         """  1103   1104         temp_fn = self._getOperatorFunction(node)  1105         left = None  1106   1107         for right in node.nodes:  1108             if left is not None:  1109                 self._visitCall(node, temp_fn, (left, right))  1110             left = right  1111   1112         self.discard_temp(temp_fn)  1113   1114     def _visitBinary(self, node):  1115   1116         """  1117         Invoke the appropriate operator module function for the operation  1118         represented by 'node'.  1119         """  1120   1121         temp_fn = self._getOperatorFunction(node)  1122         self._visitCall(node, temp_fn, (node.left, node.right))  1123         self.discard_temp(temp_fn)  1124   1125     def _visitCall(self, node, temp_fn, args):  1126   1127         """  1128         Invoke the appropriate operator module function for the operation  1129         represented by 'node', given a 'temp_fn' reference to a function, along  1130         with the 'args' (the operand nodes).  1131         """  1132   1133         # Evaluate and store the operands in temporary storage.  1134   1135         temp_list = []  1136   1137         for arg in args:  1138             self.dispatch(arg)  1139             temp_list.append(self.optimiser.optimise_temp_storage())  1140   1141         self._generateInvocation(temp_fn, temp_list)  1142   1143         # Compilation duties...  1144   1145         for temp in temp_list:  1146             self.discard_temp(temp)  1147   1148     def _generateInvocation(self, temp_fn, temp_list):  1149   1150         """  1151         Invoke the function 'temp_fn' using the operands from 'temp_list' as  1152         arguments.  1153         """  1154   1155         self._startCallFunc()  1156   1157         for i, temp in enumerate(temp_list):  1158             self.new_op(temp)  1159             self.new_op(StoreFrame(i))  1160   1161         self._endCallFuncArgs(len(temp_list))  1162         self._doCallFunc(temp_fn)  1163         self._endCallFunc(temp_fn)  1164   1165     def _getOperatorFunction(self, node, operator_name=None):  1166   1167         "Return an operator function reference for the given 'node'."  1168   1169         return self._generateOperatorFunction(operator_name or node.__class__.__name__)  1170   1171     def _getOperatorAugAssignFunction(self, node):  1172   1173         """  1174         Return an operator augmented assignment function reference for the given  1175         'node'.  1176         """  1177   1178         return self._generateOperatorFunction(node.op)  1179   1180     def _generateOperatorFunction(self, opname):  1181   1182         "Return an operator function reference for the given 'opname'."  1183   1184         operator_fn = operator_functions[opname]  1185   1186         # Get the operator module.  1187   1188         operator_module = self.importer.get_module("operator")  1189   1190         # Get the appropriate function from the operator module.  1191   1192         self.new_op(LoadAddress(operator_module[operator_fn]))  1193         return self.optimiser.optimise_temp_storage()  1194   1195     def _handleAttributeError(self, node, temp_method, handled_block):  1196   1197         """  1198         Add exception handling to the method acquisition instructions where the  1199         attribute access cannot be resolved at compile-time.  1200         """  1201   1202         if not (self.optimiser.should_optimise_known_target() and self.optimiser.is_constant_input(temp_method)):  1203             self.load_builtin("AttributeError", node)  1204             self.new_op(CheckException(target="status"))  1205             self.new_op(JumpIfTrue(handled_block, working="status"))  1206             self.new_op(RaiseException())  1207   1208     def _generateTuple(self, node):  1209   1210         "Make a tuple using the given program 'node'."  1211   1212         # Reserve space for the elements themselves.  1213   1214         self.make_instance(self.get_builtin_class("tuple"), len(node.nodes))  1215         temp = self.get_temp()  1216   1217         # Store using 0-based index values.  1218   1219         self._populateSequence(temp, node)  1220   1221         self.new_op(temp)  1222         self.discard_temp(temp)  1223   1224     def _generateList(self, node):  1225   1226         "Make a list using the given program 'node'."  1227   1228         # Make a fragment containing the list elements.  1229   1230         self.new_op(MakeFragment(len(node.nodes) + 1))  1231         temp = self.get_temp()  1232         self._populateSequence(temp, node)  1233         self.new_op(temp)  1234         self.record_value()  1235   1236         # Reserve space for _elements (the fragment reference).  1237   1238         self.make_instance(self.get_builtin_class("list"), 1)  1239         list_temp = self.get_temp()  1240         self.new_op(list_temp)  1241         self.new_op(StoreAttr(Attr(0, None, None))) # _elements is at position 0  1242         self.assign_value()  1243         self.discard_value()  1244   1245         self.new_op(list_temp)  1246         self.discard_temp(temp)  1247         self.discard_temp(list_temp)  1248   1249     def _populateSequence(self, temp, node, offset=0):  1250   1251         """  1252         Populate a sequence using the given 'temp' reference and program 'node'.  1253         """  1254   1255         for i, n in enumerate(node.nodes):  1256             self.dispatch(n)  1257             self.record_value()  1258             self._storeInSequence(temp, i, offset)  1259             self.discard_value()  1260   1261     def _storeInSequence(self, temp, i, offset=0):  1262   1263         """  1264         Store the current active value in the fragment referenced by 'temp' at  1265         position 'i' with the given starting 'offset'.  1266         """  1267   1268         self.new_op(temp)  1269         self.new_op(StoreAttr(Attr(i + offset, None, None)))  1270         self.assign_value()  1271   1272     def _generateTestBoolean(self, node, temp):  1273   1274         """  1275         Generate a test of the boolean status of the current value for the given  1276         program 'node'.  1277         """  1278   1279         # Get method on temp.  1280         # NOTE: Using __bool__ instead of __nonzero__.  1281   1282         self._generateAttr(node, "__bool__", self.attribute_load_instructions)  1283         temp_method = self.optimiser.optimise_temp_storage()  1284   1285         self._generateInvocation(temp_method, (temp,))  1286   1287         self.discard_temp(temp_method)  1288   1289         # Convert result to boolean (a StoreBoolean operation).  1290   1291         self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("True"), target="status"))  1292   1293     def _generateLoadBoolean(self, node):  1294   1295         """  1296         Generate instructions to load the appropriate value given the current  1297         boolean status.  1298         """  1299   1300         false_block = self.get_block()  1301         true_block = self.new_block()  1302         end_block = self.new_block()  1303   1304         self.new_op(JumpIfTrue(true_block, working="status"))  1305         self.new_op(LoadConst(self.importer.get_predefined_constant("False")))  1306         self.new_op(Jump(end_block))  1307   1308         self.set_block(true_block)  1309         self.new_op(LoadConst(self.importer.get_predefined_constant("True")))  1310   1311         self.set_block(end_block, [false_block, true_block])  1312   1313     def _visitPrint(self, node, function_name):  1314         self._startCallFunc()  1315         self.load_builtin(function_name, node)  1316   1317         args = [node.dest or compiler.ast.Name("None")] + node.nodes  1318   1319         temp_target, target, temp_context = self._generateCallFunc(args, node)  1320         self._doCallFunc(temp_target, target)  1321         self._endCallFunc(temp_target, temp_context)  1322   1323 # vim: tabstop=4 expandtab shiftwidth=4