Lichen

translator.py

953:28b43ef743ae
2 months ago Paul Boddie Introduced a value stack, currently unused, referenced by a function parameter alongside the ubiquitous context parameter. tagged-address-values
     1 #!/usr/bin/env python     2      3 """     4 Translate programs.     5      6 Copyright (C) 2015-2018, 2021 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 common import AccessLocation, CommonModule, CommonOutput, Location, \    23                    first, get_builtin_class, init_item, is_newer, \    24                    predefined_constants    25 from encoders import encode_access_instruction, encode_access_instruction_arg, \    26                      encode_function_pointer, encode_literal_instantiator, \    27                      encode_instantiator_pointer, encode_path, encode_symbol, \    28                      encode_type_attribute, is_type_attribute, \    29                      type_ops, typename_ops    30 from errors import InspectError, TranslateError    31 from os.path import exists, join    32 from os import makedirs    33 from referencing import Reference, combine_types    34 from results import Result    35 from transresults import TrConstantValueRef, TrInstanceRef, \    36                          TrLiteralSequenceRef, TrResolvedNameRef, \    37                          AliasResult, AttrResult, Expression, InstantiationResult, \    38                          InvocationResult, LogicalOperationResult, \    39                          LogicalResult, NegationResult, PredefinedConstantRef, \    40                          ReturnRef    41 from StringIO import StringIO    42 import compiler    43 import sys    44     45 class Translator(CommonOutput):    46     47     "A program translator."    48     49     def __init__(self, importer, deducer, optimiser, output):    50         self.importer = importer    51         self.deducer = deducer    52         self.optimiser = optimiser    53         self.output = output    54     55     def to_output(self, reset=False, debug=False, gc_sections=False):    56     57         "Write a program to the configured output directory."    58     59         # Make a directory for the final sources.    60     61         output = join(self.output, "src")    62     63         if not exists(output):    64             makedirs(output)    65     66         # Clean the output directory of irrelevant data.    67     68         self.check_output("debug=%r gc_sections=%r" % (debug, gc_sections))    69     70         for module in self.importer.modules.values():    71             output_filename = join(output, "%s.c" % module.name)    72     73             # Do not generate modules in the native package. They are provided    74             # by native functionality source files.    75     76             parts = module.name.split(".")    77     78             if parts[0] != "native" and \    79                (reset or is_newer(module.filename, output_filename)):    80     81                 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser)    82                 tm.translate(module.filename, output_filename)    83     84     85     86 def make_expression(expr):    87     88     "Make a new expression from the existing 'expr'."    89     90     if isinstance(expr, Result):    91         return expr    92     else:    93         return Expression(str(expr))    94     95     96     97 # The actual translation process itself.    98     99 class TranslatedModule(CommonModule):   100    101     "A module translator."   102    103     def __init__(self, name, importer, deducer, optimiser):   104         CommonModule.__init__(self, name, importer)   105         self.deducer = deducer   106         self.optimiser = optimiser   107    108         # Output stream.   109    110         self.out_toplevel = self.out = None   111         self.indent = 0   112         self.tabstop = "    "   113    114         # Recorded namespaces.   115    116         self.namespaces = []   117         self.in_conditional = False   118         self.in_parameter_list = False   119    120         # Exception raising adjustments.   121    122         self.in_try_finally = False   123         self.in_try_except = False   124    125         # Attribute access and accessor counting.   126    127         self.attr_accesses = {}   128         self.attr_accessors = {}   129    130         # Special variable usage.   131    132         self.temp_usage = {}   133    134         # Initialise some data used for attribute access generation.   135    136         self.init_substitutions()   137    138     def __repr__(self):   139         return "TranslatedModule(%r, %r)" % (self.name, self.importer)   140    141     def translate(self, filename, output_filename):   142    143         """   144         Parse the file having the given 'filename', writing the translation to   145         the given 'output_filename'.   146         """   147    148         self.parse_file(filename)   149    150         # Collect function namespaces for separate processing.   151    152         self.record_namespaces(self.astnode)   153    154         # Reset the lambda naming (in order to obtain the same names again) and   155         # translate the program.   156    157         self.reset_lambdas()   158    159         self.out_toplevel = self.out = open(output_filename, "w")   160         try:   161             self.start_output()   162    163             # Process namespaces, writing the translation.   164    165             for path, node in self.namespaces:   166                 self.process_namespace(path, node)   167    168             # Process the module namespace including class namespaces.   169    170             self.process_namespace([], self.astnode)   171    172         finally:   173             self.out.close()   174    175     def have_object(self):   176    177         "Return whether a namespace is a recorded object."   178    179         return self.importer.objects.get(self.get_namespace_path())   180    181     def get_builtin_class(self, name):   182    183         "Return a reference to the actual object providing 'name'."   184    185         return self.importer.get_object(get_builtin_class(name))   186    187     def is_method(self, path):   188    189         "Return whether 'path' is a method."   190    191         class_name, method_name = path.rsplit(".", 1)   192         return self.importer.classes.has_key(class_name) and class_name or None   193    194     def in_method(self):   195    196         "Return whether the current namespace provides a method."   197    198         return self.in_function and self.is_method(self.get_namespace_path())   199    200     # Namespace recording.   201    202     def record_namespaces(self, node):   203    204         "Process the program structure 'node', recording namespaces."   205    206         for n in node.getChildNodes():   207             self.record_namespaces_in_node(n)   208    209     def record_namespaces_in_node(self, node):   210    211         "Process the program structure 'node', recording namespaces."   212    213         # Function namespaces within modules, classes and other functions.   214         # Functions appearing within conditional statements are given arbitrary   215         # names.   216    217         if isinstance(node, compiler.ast.Function):   218             self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name)   219    220         elif isinstance(node, compiler.ast.Lambda):   221             self.record_function_node(node, self.get_lambda_name())   222    223         # Classes are visited, but may be ignored if inside functions.   224    225         elif isinstance(node, compiler.ast.Class):   226             self.enter_namespace(node.name)   227             if self.have_object():   228                 self.record_namespaces(node)   229             self.exit_namespace()   230    231         # Conditional nodes are tracked so that function definitions may be   232         # handled. Since "for" loops are converted to "while" loops, they are   233         # included here.   234    235         elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)):   236             in_conditional = self.in_conditional   237             self.in_conditional = True   238             self.record_namespaces(node)   239             self.in_conditional = in_conditional   240    241         # All other nodes are processed depth-first.   242    243         else:   244             self.record_namespaces(node)   245    246     def record_function_node(self, n, name):   247    248         """   249         Record the given function, lambda, if expression or list comprehension   250         node 'n' with the given 'name'.   251         """   252    253         self.in_function = True   254         self.enter_namespace(name)   255    256         if self.have_object():   257    258             # Record the namespace path and the node itself.   259    260             self.namespaces.append((self.namespace_path[:], n))   261             self.record_namespaces_in_node(n.code)   262    263         self.exit_namespace()   264         self.in_function = False   265    266     # Constant referencing.   267    268     def get_literal_instance(self, n, name=None):   269    270         """   271         For node 'n', return a reference for the type of the given 'name', or if   272         'name' is not specified, deduce the type from the value.   273         """   274    275         # Handle stray None constants (Sliceobj seems to produce them).   276    277         if name is None and n.value is None:   278             return self.process_name_node(compiler.ast.Name("None"))   279    280         if name in ("dict", "list", "tuple"):   281             ref = self.get_builtin_class(name)   282             return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef)   283         else:   284             value, typename, encoding = self.get_constant_value(n.value, n.literals)   285             ref = self.get_builtin_class(typename)   286             value_type = ref.get_origin()   287    288             path = self.get_namespace_path()   289    290             # Obtain the local numbering of the constant and thus the   291             # locally-qualified name.   292    293             local_number = self.importer.all_constants[path][(value, value_type, encoding)]   294             constant_name = "$c%d" % local_number   295             objpath = self.get_object_path(constant_name)   296    297             # Obtain the unique identifier for the constant.   298    299             number = self.optimiser.constant_numbers[objpath]   300             return TrConstantValueRef(constant_name, ref.instance_of(), value, number)   301    302     # Namespace translation.   303    304     def process_namespace(self, path, node):   305    306         """   307         Process the namespace for the given 'path' defined by the given 'node'.   308         """   309    310         self.namespace_path = path   311    312         if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)):   313             self.in_function = True   314             self.process_function_body_node(node)   315         else:   316             self.in_function = False   317             self.function_target = 0   318             self.max_function_target = 0   319             self.context_index = 0   320             self.max_context_index = 0   321             self.accessor_index = 0   322             self.max_accessor_index = 0   323             self.start_module()   324             self.process_structure(node)   325             self.end_module()   326    327     def process_structure(self, node):   328    329         "Process the given 'node' or result."   330    331         # Handle processing requests on results.   332    333         if isinstance(node, Result):   334             return node   335    336         # Handle processing requests on nodes.   337    338         else:   339             l = CommonModule.process_structure(self, node)   340    341             # Return indications of return statement usage.   342    343             if l and isinstance(l[-1], ReturnRef):   344                 return l[-1]   345             else:   346                 return None   347    348     def process_structure_node(self, n):   349    350         "Process the individual node 'n'."   351    352         # Plain statements emit their expressions.   353    354         if isinstance(n, compiler.ast.Discard):   355             expr = self.process_structure_node(n.expr)   356             self.statement(expr)   357    358         # Module import declarations.   359    360         elif isinstance(n, compiler.ast.From):   361             self.process_from_node(n)   362    363         # Nodes using operator module functions.   364    365         elif isinstance(n, compiler.ast.Operator):   366             return self.process_operator_node(n)   367    368         elif isinstance(n, compiler.ast.AugAssign):   369             self.process_augassign_node(n)   370    371         elif isinstance(n, compiler.ast.Compare):   372             return self.process_compare_node(n)   373    374         elif isinstance(n, compiler.ast.Slice):   375             return self.process_slice_node(n)   376    377         elif isinstance(n, compiler.ast.Sliceobj):   378             return self.process_sliceobj_node(n)   379    380         elif isinstance(n, compiler.ast.Subscript):   381             return self.process_subscript_node(n)   382    383         # Classes are visited, but may be ignored if inside functions.   384    385         elif isinstance(n, compiler.ast.Class):   386             self.process_class_node(n)   387    388         # Functions within namespaces have any dynamic defaults initialised.   389    390         elif isinstance(n, compiler.ast.Function):   391             self.process_function_node(n)   392    393         # Lambdas are replaced with references to separately-generated   394         # functions.   395    396         elif isinstance(n, compiler.ast.Lambda):   397             return self.process_lambda_node(n)   398    399         # Assignments.   400    401         elif isinstance(n, compiler.ast.Assign):   402    403             # Handle each assignment node.   404    405             for node in n.nodes:   406                 self.process_assignment_node(node, n.expr)   407    408         # Accesses.   409    410         elif isinstance(n, compiler.ast.Getattr):   411             return self.process_attribute_access(n)   412    413         # Names.   414    415         elif isinstance(n, compiler.ast.Name):   416             return self.process_name_node(n)   417    418         # Loops and conditionals.   419    420         elif isinstance(n, compiler.ast.For):   421             self.process_for_node(n)   422    423         elif isinstance(n, compiler.ast.While):   424             self.process_while_node(n)   425    426         elif isinstance(n, compiler.ast.If):   427             self.process_if_node(n)   428    429         elif isinstance(n, (compiler.ast.And, compiler.ast.Or)):   430             return self.process_logical_node(n)   431    432         elif isinstance(n, compiler.ast.Not):   433             return self.process_not_node(n)   434    435         # Exception control-flow tracking.   436    437         elif isinstance(n, compiler.ast.TryExcept):   438             self.process_try_node(n)   439    440         elif isinstance(n, compiler.ast.TryFinally):   441             self.process_try_finally_node(n)   442    443         # Control-flow modification statements.   444    445         elif isinstance(n, compiler.ast.Break):   446             self.writestmt("break;")   447    448         elif isinstance(n, compiler.ast.Continue):   449             self.writestmt("continue;")   450    451         elif isinstance(n, compiler.ast.Raise):   452             self.process_raise_node(n)   453    454         elif isinstance(n, compiler.ast.Return):   455             return self.process_return_node(n)   456    457         # Print statements.   458    459         elif isinstance(n, (compiler.ast.Print, compiler.ast.Printnl)):   460             self.statement(self.process_print_node(n))   461    462         # Invocations.   463    464         elif isinstance(n, compiler.ast.CallFunc):   465             return self.process_invocation_node(n)   466    467         elif isinstance(n, compiler.ast.Keyword):   468             return self.process_structure_node(n.expr)   469    470         # Constant usage.   471    472         elif isinstance(n, compiler.ast.Const):   473             return self.get_literal_instance(n)   474    475         elif isinstance(n, compiler.ast.Dict):   476             return self.get_literal_instance(n, "dict")   477    478         elif isinstance(n, compiler.ast.List):   479             return self.get_literal_instance(n, "list")   480    481         elif isinstance(n, compiler.ast.Tuple):   482             return self.get_literal_instance(n, "tuple")   483    484         # All other nodes are processed depth-first.   485    486         else:   487             return self.process_structure(n)   488    489     def process_assignment_node(self, n, expr):   490    491         "Process the individual node 'n' to be assigned the contents of 'expr'."   492    493         # Names and attributes are assigned the entire expression.   494    495         if isinstance(n, compiler.ast.AssName):   496             name_ref = self.process_name_node(n, self.process_structure_node(expr))   497             self.statement(name_ref)   498    499             # Employ guards after assignments if required.   500    501             if expr and name_ref.is_name():   502                 self.generate_guard(name_ref.name)   503    504         elif isinstance(n, compiler.ast.AssAttr):   505             in_assignment = self.in_assignment   506             self.in_assignment = self.process_structure_node(expr)   507             self.statement(self.process_attribute_access(n))   508             self.in_assignment = in_assignment   509    510         # Lists and tuples are matched against the expression and their   511         # items assigned to expression items.   512    513         elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)):   514             self.process_assignment_node_items(n, expr)   515    516         # Slices and subscripts are permitted within assignment nodes.   517    518         elif isinstance(n, compiler.ast.Slice):   519             self.statement(self.process_slice_node(n, expr))   520    521         elif isinstance(n, compiler.ast.Subscript):   522             self.statement(self.process_subscript_node(n, expr))   523    524     def process_attribute_access(self, n):   525    526         "Process the given attribute access node 'n'."   527    528         # Obtain any completed chain and return the reference to it.   529    530         attr_expr = self.process_attribute_chain(n)   531         if self.have_access_expression(n):   532             return attr_expr   533    534         # Where the start of the chain of attributes has been reached, process   535         # the complete access.   536    537         name_ref = attr_expr and attr_expr.is_name() and attr_expr   538         name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref) or None   539    540         location = self.get_access_location(name, self.attrs)   541         refs = self.get_referenced_attributes(location)   542    543         # Generate access instructions.   544    545         subs = {   546             "<expr>" : attr_expr,   547             "<name>" : attr_expr,   548             "<assexpr>" : self.in_assignment,   549             }   550    551         subs.update(self.temp_subs)   552         subs.update(self.op_subs)   553    554         output = []   555         substituted = set()   556    557         # The context set or retrieved will be that used by any enclosing   558         # invocation.   559    560         accessor_index = self.accessor_index   561         context_index = self.context_index   562         context_identity = None   563         context_identity_verified = False   564         final_identity = None   565         accessor_test = False   566         accessor_stored = False   567    568         # Obtain encoded versions of each instruction, accumulating temporary   569         # variables.   570    571         for instruction in self.deducer.access_instructions[location]:   572    573             # Intercept a special instruction identifying the context.   574    575             if instruction[0] in ("<context_identity>", "<context_identity_verified>"):   576                 context_identity, _substituted = \   577                     encode_access_instruction_arg(instruction[1], subs, instruction[0],   578                                                   accessor_index, context_index)   579                 context_identity_verified = instruction[0] == "<context_identity_verified>"   580                 continue   581    582             # Intercept a special instruction identifying the target. The value   583             # is not encoded since it is used internally.   584    585             elif instruction[0] == "<final_identity>":   586                 final_identity = instruction[1]   587                 continue   588    589             # Modify test instructions.   590    591             elif instruction[0] in typename_ops or instruction[0] in type_ops:   592                 instruction = ("__to_error", instruction)   593                 accessor_test = True   594    595             # Intercept accessor storage.   596    597             elif instruction[0] == "<set_accessor>":   598                 accessor_stored = True   599    600             # Collect the encoded instruction, noting any temporary variables   601             # required by it.   602    603             encoded, _substituted = encode_access_instruction(instruction, subs,   604                                         accessor_index, context_index)   605             output.append(encoded)   606             substituted.update(_substituted)   607    608         # Record temporary name usage.   609    610         for sub in substituted:   611             if self.temp_subs.has_key(sub):   612                 self.record_temp(self.temp_subs[sub])   613    614         # Get full final identity details.   615    616         if final_identity and not refs:   617             refs = set([self.importer.identify(final_identity)])   618    619         del self.attrs[0]   620         return AttrResult(output, refs, location,   621                           context_identity, context_identity_verified,   622                           accessor_test, accessor_stored)   623    624     def init_substitutions(self):   625    626         """   627         Initialise substitutions, defining temporary variable mappings, some of   628         which are also used as substitutions, together with operation mappings   629         used as substitutions in instructions defined by the optimiser.   630         """   631    632         self.temp_subs = {   633    634             # Substitutions used by instructions.   635    636             "<private_context>" : "__tmp_private_context",   637             "<target_accessor>" : "__tmp_target_value",   638    639             # Mappings to be replaced by those given below.   640    641             "<accessor>" : "__tmp_values",   642             "<context>" : "__tmp_contexts",   643             "<test_context_revert>" : "__tmp_contexts",   644             "<test_context_static>" : "__tmp_contexts",   645             "<set_context>" : "__tmp_contexts",   646             "<set_private_context>" : "__tmp_private_context",   647             "<set_accessor>" : "__tmp_values",   648             "<set_target_accessor>" : "__tmp_target_value",   649             }   650    651         self.op_subs = {   652             "<accessor>" : "__get_accessor",   653             "<context>" : "__get_context",   654             "<test_context_revert>" : "__test_context_revert",   655             "<test_context_static>" : "__test_context_static",   656             "<set_context>" : "__set_context",   657             "<set_private_context>" : "__set_private_context",   658             "<set_accessor>" : "__set_accessor",   659             "<set_target_accessor>" : "__set_target_accessor",   660             }   661    662     def get_referenced_attributes(self, location):   663    664         """   665         Convert 'location' to the form used by the deducer and retrieve any   666         identified attributes.   667         """   668    669         # Determine whether any deduced references refer to the accessed   670         # attribute.   671    672         attrnames = location.attrnames   673         attrnames = attrnames and attrnames.split(".")   674         remaining = attrnames and len(attrnames) > 1   675    676         access_location = self.deducer.const_accesses.get(location)   677    678         if remaining and not access_location:   679             return set()   680    681         return self.deducer.get_references_for_access(access_location or location)   682    683     def get_referenced_attribute_invocations(self, location):   684    685         """   686         Convert 'location' to the form used by the deducer and retrieve any   687         identified attribute invocation details.   688         """   689    690         access_location = self.deducer.const_accesses.get(location)   691         return self.deducer.reference_invocations_unsuitable.get(access_location or location)   692    693     def get_accessor_kinds(self, location):   694    695         "Return the accessor kinds for 'location'."   696    697         return self.deducer.accessor_kinds.get(location)   698    699     def get_access_location(self, name, attrnames=None):   700    701         """   702         Using the current namespace, the given 'name', and the 'attrnames'   703         employed in an access, return the access location.   704         """   705    706         path = self.get_path_for_access()   707    708         # Get the location used by the deducer and optimiser and find any   709         # recorded access.   710    711         attrnames = attrnames and ".".join(self.attrs)   712         access_number = self.get_access_number(path, name, attrnames)   713         self.update_access_number(path, name, attrnames)   714         return AccessLocation(path, name, attrnames, access_number)   715    716     def get_access_number(self, path, name, attrnames):   717         access = name, attrnames   718         if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access):   719             return self.attr_accesses[path][access]   720         else:   721             return 0   722    723     def update_access_number(self, path, name, attrnames):   724         access = name, attrnames   725         if name:   726             init_item(self.attr_accesses, path, dict)   727             init_item(self.attr_accesses[path], access, lambda: 0)   728             self.attr_accesses[path][access] += 1   729    730     def get_accessor_location(self, name):   731    732         """   733         Using the current namespace and the given 'name', return the accessor   734         location.   735         """   736    737         path = self.get_path_for_access()   738    739         # Get the location used by the deducer and optimiser and find any   740         # recorded accessor.   741    742         version = self.get_accessor_number(path, name)   743         self.update_accessor_number(path, name)   744         return Location(path, name, None, version)   745    746     def get_accessor_number(self, path, name):   747         if self.attr_accessors.has_key(path) and self.attr_accessors[path].has_key(name):   748             return self.attr_accessors[path][name]   749         else:   750             return 0   751    752     def update_accessor_number(self, path, name):   753         if name:   754             init_item(self.attr_accessors, path, dict)   755             init_item(self.attr_accessors[path], name, lambda: 0)   756             self.attr_accessors[path][name] += 1   757    758     def process_class_node(self, n):   759    760         "Process the given class node 'n'."   761    762         class_name = self.get_object_path(n.name)   763    764         # Where a class is set conditionally or where the name may refer to   765         # different values, assign the name.   766    767         ref = self.importer.identify(class_name)   768    769         if not ref.static():   770             self.process_assignment_for_object(n.name,   771                 make_expression("__ATTRVALUE(&%s)" % encode_path(class_name)))   772    773         self.enter_namespace(n.name)   774    775         if self.have_object():   776             self.write_comment("Class: %s" % class_name)   777    778             self.initialise_inherited_members(class_name)   779    780             self.process_structure(n)   781             self.write_comment("End class: %s" % class_name)   782    783         self.exit_namespace()   784    785     def initialise_inherited_members(self, class_name):   786    787         "Initialise members of 'class_name' inherited from its ancestors."   788    789         for name, path in self.importer.all_class_attrs[class_name].items():   790             target = "%s.%s" % (class_name, name)   791    792             # Ignore attributes with definitions.   793    794             ref = self.importer.identify(target)   795             if ref:   796                 continue   797    798             # Ignore special type attributes.   799    800             if is_type_attribute(name):   801                 continue   802    803             # Reference inherited attributes.   804    805             ref = self.importer.identify(path)   806             if ref and not ref.static():   807                 parent, attrname = path.rsplit(".", 1)   808    809                 self.writestmt("__store_via_object(&%s, %s, __load_via_object(&%s, %s));" % (   810                     encode_path(class_name), name,   811                     encode_path(parent), attrname   812                     ))   813    814     def process_from_node(self, n):   815    816         "Process the given node 'n', importing from another module."   817    818         path = self.get_namespace_path()   819    820         # Attempt to obtain the referenced objects.   821    822         for name, alias in n.names:   823             if name == "*":   824                 raise InspectError("Only explicitly specified names can be imported from modules.", path, n)   825    826             # Obtain the path of the assigned name.   827    828             objpath = self.get_object_path(alias or name)   829    830             # Obtain the identity of the name.   831    832             ref = self.importer.identify(objpath)   833    834             # Where the name is not static, assign the value.   835    836             if ref and not ref.static() and ref.get_name():   837                 self.writestmt("%s;" %    838                     TrResolvedNameRef(alias or name, Reference("<var>", None, objpath),   839                                       expr=TrResolvedNameRef(name, ref)))   840    841     def process_function_body_node(self, n):   842    843         """   844         Process the given function, lambda, if expression or list comprehension   845         node 'n', generating the body.   846         """   847    848         function_name = self.get_namespace_path()   849         self.start_function(function_name)   850    851         # Process the function body.   852    853         in_conditional = self.in_conditional   854         self.in_conditional = False   855         self.function_target = 0   856         self.max_function_target = 0   857         self.context_index = 0   858         self.max_context_index = 0   859         self.accessor_index = 0   860         self.max_accessor_index = 0   861    862         # Volatile locals for exception handling.   863    864         self.volatile_locals = set()   865    866         # Process any guards defined for the parameters.   867    868         for name in self.importer.function_parameters.get(function_name):   869             self.generate_guard(name)   870    871         # Also support self in methods, since some mix-in methods may only work   872         # with certain descendant classes.   873    874         if self.in_method():   875             self.generate_guard("self")   876    877         # Make assignments for .name entries in the parameters, provided this is   878         # a method.   879    880         if self.in_method():   881             for name in self.importer.function_attr_initialisers.get(function_name) or []:   882                 self.process_assignment_node(   883                     compiler.ast.AssAttr(compiler.ast.Name("self"), name, "OP_ASSIGN"),   884                     compiler.ast.Name(name))   885    886         # Produce the body and any additional return statement.   887    888         expr = self.process_structure_node(n.code) or \   889                self.in_method() and \   890                    function_name.rsplit(".", 1)[-1] == "__init__" and \   891                    TrResolvedNameRef("self", self.importer.function_locals[function_name]["self"]) or \   892                PredefinedConstantRef("None")   893    894         if not isinstance(expr, ReturnRef):   895             self.writestmt("return %s;" % expr)   896    897         self.in_conditional = in_conditional   898    899         self.end_function(function_name)   900    901     def generate_guard(self, name):   902    903         """   904         Get the accessor details for 'name', found in the current namespace, and   905         generate any guards defined for it.   906         """   907    908         # Obtain the location, keeping track of assignment versions.   909    910         location = self.get_accessor_location(name)   911         test = self.deducer.accessor_guard_tests.get(location)   912    913         # Generate any guard from the deduced information.   914    915         if test:   916             guard, guard_type = test   917    918             if guard == "specific":   919                 ref = first(self.deducer.accessor_all_types[location])   920                 argstr = "&%s" % encode_path(ref.get_origin())   921             elif guard == "common":   922                 ref = first(self.deducer.accessor_all_general_types[location])   923                 argstr = encode_path(encode_type_attribute(ref.get_origin()))   924             else:   925                 return   926    927             # Write a test that raises a TypeError upon failure.   928    929             self.writestmt("if (!__test_%s_%s(__VALUE(%s), %s)) __raise_type_error();" % (   930                 guard, guard_type, encode_path(name), argstr))   931    932     def process_function_node(self, n):   933    934         """   935         Process the given function, lambda, if expression or list comprehension   936         node 'n', generating any initialisation statements.   937         """   938    939         # Where a function is declared conditionally, use a separate name for   940         # the definition, and assign the definition to the stated name.   941    942         original_name = n.name   943    944         if self.in_conditional or self.in_function:   945             name = self.get_lambda_name()   946         else:   947             name = n.name   948    949         objpath = self.get_object_path(name)   950    951         # Obtain details of the defaults.   952    953         defaults = self.process_function_defaults(n, name, objpath)   954         if defaults:   955             for default in defaults:   956                 self.writeline("%s;" % default)   957    958         # Where a function is set conditionally or where the name may refer to   959         # different values, assign the name.   960    961         ref = self.importer.identify(objpath)   962    963         if self.in_conditional or self.in_function:   964             self.process_assignment_for_object(original_name, compiler.ast.Name(name))   965         elif not ref.static():   966             context = self.is_method(objpath)   967    968             self.process_assignment_for_object(original_name,   969                 make_expression("__ATTRVALUE(&%s)" % encode_path(objpath)))   970    971     def process_function_defaults(self, n, name, objpath, instance_name=None):   972    973         """   974         Process the given function or lambda node 'n', initialising defaults   975         that are dynamically set. The given 'name' indicates the name of the   976         function. The given 'objpath' indicates the origin of the function.   977         The given 'instance_name' indicates the name of any separate instance   978         of the function created to hold the defaults.   979    980         Return a list of operations setting defaults on a function instance.   981         """   982    983         function_name = self.get_object_path(name)   984         function_defaults = self.importer.function_defaults.get(function_name)   985         if not function_defaults:   986             return None   987    988         # Determine whether any unidentified defaults are involved.   989    990         for argname, default in function_defaults:   991             if not default.static():   992                 break   993         else:   994             return None   995    996         # Handle bound methods.   997    998         if not instance_name:   999             instance_name = "&%s" % encode_path(objpath)  1000         else:  1001             instance_name = "__VALUE(%s)" % instance_name  1002   1003         # Where defaults are involved but cannot be identified, obtain a new  1004         # instance of the lambda and populate the defaults.  1005   1006         defaults = []  1007   1008         # Join the original defaults with the inspected defaults.  1009   1010         original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default]  1011   1012         for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)):  1013   1014             # Obtain any reference for the default.  1015   1016             if original:  1017                 argname, default = original  1018                 name_ref = self.process_structure_node(default)  1019             elif inspected:  1020                 argname, default = inspected  1021                 name_ref = TrResolvedNameRef(argname, default)  1022             else:  1023                 continue  1024   1025             # Generate default initialisers except when constants are employed.  1026             # Constants should be used when populating the function structures.  1027   1028             if name_ref and not isinstance(name_ref, TrConstantValueRef):  1029                 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref))  1030   1031         return defaults  1032   1033     def process_if_node(self, n):  1034   1035         """  1036         Process the given "if" node 'n'.  1037         """  1038   1039         first = True  1040         for test, body in n.tests:  1041             test_ref = self.process_structure_node(test)  1042             self.start_if(first, test_ref)  1043   1044             in_conditional = self.in_conditional  1045             self.in_conditional = True  1046             self.process_structure_node(body)  1047             self.in_conditional = in_conditional  1048   1049             self.end_if()  1050             first = False  1051   1052         if n.else_:  1053             self.start_else()  1054             self.process_structure_node(n.else_)  1055             self.end_else()  1056   1057         print >>self.out  1058   1059     def process_invocation_node(self, n):  1060   1061         "Process the given invocation node 'n'."  1062   1063         # Process the expression.  1064   1065         expr = self.process_structure_node(n.node)  1066   1067         # Obtain details of the invocation expression.  1068   1069         objpath = expr.get_origin()  1070         location = expr.access_location()  1071         refs = expr.references()  1072   1073         # Identified target details.  1074   1075         target = None  1076         target_structure = None  1077   1078         # Specific function target information.  1079   1080         function = None  1081   1082         # Instantiation involvement.  1083   1084         instantiation = False  1085         literal_instantiation = False  1086   1087         # Invocation requirements.  1088   1089         context_required = True  1090         have_access_context = isinstance(expr, AttrResult)  1091   1092         # The context identity is merely the thing providing the context.  1093         # A verified context is one that does not need further testing for  1094         # suitability.  1095   1096         context_identity = have_access_context and expr.context()  1097         context_verified = have_access_context and expr.context_verified()  1098   1099         # The presence of any test operations in the accessor expression.  1100         # With such operations present, the expression cannot be eliminated.  1101   1102         tests_accessor = have_access_context and expr.tests_accessor()  1103         stores_accessor = have_access_context and expr.stores_accessor()  1104   1105         # Parameter details and parameter list dimensions.  1106   1107         parameters = None  1108         num_parameters = None  1109         num_defaults = None  1110   1111         # Obtain details of the callable and of its parameters.  1112   1113         # Literals may be instantiated specially.  1114   1115         if expr.is_name() and expr.name.startswith("$L") and objpath:  1116             instantiation = literal_instantiation = objpath  1117             target = encode_literal_instantiator(objpath)  1118             context_required = False  1119   1120         # Identified targets employ function pointers directly.  1121   1122         elif objpath:  1123             parameters = self.importer.function_parameters.get(objpath)  1124             function_defaults = self.importer.function_defaults.get(objpath)  1125             num_parameters = parameters and len(parameters) or 0  1126             num_defaults = function_defaults and len(function_defaults) or 0  1127   1128             # Class invocation involves instantiators.  1129   1130             if expr.has_kind("<class>"):  1131                 instantiation = objpath  1132                 target = encode_instantiator_pointer(objpath)  1133                 init_ref = self.importer.all_class_attrs[objpath]["__init__"]  1134                 target_structure = "&%s" % encode_path(init_ref)  1135                 context_required = False  1136   1137             # Only plain functions and bound methods employ function pointers.  1138   1139             elif expr.has_kind("<function>"):  1140                 function = objpath  1141   1142                 # Test for functions and methods.  1143   1144                 context_required = self.is_method(objpath)  1145   1146                 accessor_kinds = location and self.get_accessor_kinds(location)  1147   1148                 instance_accessor = accessor_kinds and \  1149                                     len(accessor_kinds) == 1 and \  1150                                     first(accessor_kinds) == "<instance>"  1151   1152                 # Only identify certain bound methods or functions.  1153   1154                 if not context_required or instance_accessor:  1155                     target = encode_function_pointer(objpath)  1156   1157                 # Access bound method defaults even if it is not clear whether  1158                 # the accessor is appropriate.  1159   1160                 target_structure = "&%s" % encode_path(objpath)  1161   1162         # Other targets are retrieved at run-time.  1163   1164         else:  1165             if location:  1166                 attrnames = location.attrnames  1167                 attrname = attrnames and attrnames.rsplit(".", 1)[-1]  1168   1169                 # Determine common aspects of any identifiable targets.  1170   1171                 if attrname or refs:  1172                     all_params = set()  1173                     all_defaults = set()  1174                     min_params = set()  1175                     max_params = set()  1176   1177                     # Employ references from the expression or find all  1178                     # possible attributes for the given attribute name.  1179   1180                     refs = refs or self.get_attributes_for_attrname(attrname)  1181   1182                     # Obtain parameters and defaults for each possible target.  1183   1184                     for ref in refs:  1185                         origin = ref.get_origin()  1186                         params = self.importer.function_parameters.get(origin)  1187   1188                         defaults = self.importer.function_defaults.get(origin)  1189                         if defaults is not None:  1190                             all_defaults.add(tuple(defaults))  1191   1192                         if params is not None:  1193                             all_params.add(tuple(params))  1194                             min_params.add(len(params) - (defaults and len(defaults) or 0))  1195                             max_params.add(len(params))  1196                         else:  1197                             refs = set()  1198                             break  1199   1200                     # Where the parameters and defaults are always the same,  1201                     # permit populating them in advance.  1202   1203                     if refs:  1204                         if self.uses_keyword_arguments(n):  1205                             if len(all_params) == 1 and (not all_defaults or len(all_defaults) == 1):  1206                                 parameters = first(all_params)  1207                                 function_defaults = all_defaults and first(all_defaults) or []  1208                                 num_parameters = parameters and len(parameters) or 0  1209                                 num_defaults = function_defaults and len(function_defaults) or 0  1210                         else:  1211                             if len(min_params) == 1 and len(max_params) == 1:  1212                                 num_parameters = first(max_params)  1213                                 num_defaults = first(max_params) - first(min_params)  1214   1215             # Some information about the target may be available and be used to  1216             # provide warnings about argument compatibility.  1217   1218             if self.importer.give_warning("args"):  1219                 unsuitable = self.get_referenced_attribute_invocations(location)  1220   1221                 if unsuitable:  1222                     for ref in unsuitable:  1223                         _objpath = ref.get_origin()  1224                         print >>sys.stderr, \  1225                             "In %s, at line %d, inappropriate number of " \  1226                             "arguments given. Need %d arguments to call %s." % (  1227                             self.get_namespace_path(), n.lineno,  1228                             len(self.importer.function_parameters[_objpath]),  1229                             _objpath)  1230   1231         # Logical statement about available parameter information.  1232   1233         known_parameters = num_parameters is not None  1234   1235         # The source of context information: target or temporary.  1236   1237         need_context_target = context_required and not have_access_context  1238   1239         need_context_stored = context_required and context_identity and \  1240                               context_identity.startswith("__get_context")  1241   1242         # Determine any readily-accessible target identity.  1243   1244         target_named = expr.is_name() and str(expr) or None  1245         target_identity = target or target_named  1246   1247         # Use of target information to populate defaults.  1248   1249         defaults_target_var = not (parameters and function_defaults is not None) and \  1250                               known_parameters and len(n.args) < num_parameters  1251   1252         # Use of a temporary target variable in these situations:  1253         #  1254         # A target provided by an expression needed for defaults.  1255         #  1256         # A target providing the context but not using a name to do so.  1257         #  1258         # A target expression involving the definition of a context which may  1259         # then be evaluated and stored to ensure that the context is available  1260         # during argument evaluation.  1261         #  1262         # An expression featuring an accessor test.  1263   1264         need_target_stored = defaults_target_var and not target_identity or \  1265                              need_context_target and not target_identity or \  1266                              need_context_stored or \  1267                              tests_accessor and not target  1268   1269         # Define stored target details.  1270   1271         target_stored = "__tmp_targets[%d]" % self.function_target  1272         target_var = need_target_stored and target_stored or target_identity  1273   1274         if need_target_stored:  1275             self.record_temp("__tmp_targets")  1276   1277         if need_context_stored:  1278             self.record_temp("__tmp_contexts")  1279   1280         if stores_accessor:  1281             self.record_temp("__tmp_values")  1282   1283         # Arguments are presented in a temporary frame array with any context  1284         # always being the first argument after the value stack. Where the  1285         # context would be unused, it may be set to null.  1286   1287         if context_required:  1288             if have_access_context:  1289                 context_arg = context_identity  1290             else:  1291                 context_arg = "__CONTEXT_AS_VALUE(%s)" % target_var  1292         else:  1293             context_arg = "__NULL"  1294   1295         # Introduce the value stack and any context.  1296   1297         args = ["__stack", context_arg]  1298         reserved_args = 2  1299   1300         # Complete the array with null values, permitting tests for a complete  1301         # set of arguments.  1302   1303         args += [None] * (num_parameters is None and len(n.args) or num_parameters is not None and num_parameters or 0)  1304         kwcodes = []  1305         kwargs = []  1306   1307         # Any invocations in the arguments will store target details in a  1308         # different location.  1309   1310         function_target = self.function_target  1311         context_index = self.context_index  1312         accessor_index = self.accessor_index  1313   1314         if need_target_stored:  1315             self.next_target()  1316   1317         if need_context_stored:  1318             self.next_context()  1319   1320         if stores_accessor:  1321             self.next_accessor()  1322   1323         in_parameter_list = self.in_parameter_list  1324         self.in_parameter_list = True  1325   1326         for i, arg in enumerate(n.args):  1327             argexpr = self.process_structure_node(arg)  1328   1329             # Store a keyword argument, either in the argument list or  1330             # in a separate keyword argument list for subsequent lookup.  1331   1332             if isinstance(arg, compiler.ast.Keyword):  1333   1334                 # With knowledge of the target, store the keyword  1335                 # argument directly.  1336   1337                 if parameters:  1338                     try:  1339                         argnum = parameters.index(arg.name)  1340                     except ValueError:  1341                         raise TranslateError("Argument %s is not recognised." % arg.name,  1342                                              self.get_namespace_path(), n)  1343                     args[argnum + reserved_args] = str(argexpr)  1344   1345                 # Otherwise, store the details in a separate collection.  1346   1347                 else:  1348                     kwargs.append(str(argexpr))  1349                     kwcodes.append("{%s, %s}" % (  1350                         encode_ppos(arg.name), encode_pcode(arg.name)))  1351   1352             # Store non-keyword arguments in the argument list, rejecting  1353             # superfluous arguments.  1354   1355             else:  1356                 try:  1357                     args[i + reserved_args] = str(argexpr)  1358                 except IndexError:  1359                     raise TranslateError("Too many arguments specified.",  1360                                          self.get_namespace_path(), n)  1361   1362         # Reference the current target again.  1363   1364         self.in_parameter_list = in_parameter_list  1365   1366         if not self.in_parameter_list:  1367             self.function_target = function_target  1368             self.context_index = context_index  1369             self.accessor_index = accessor_index  1370   1371         # Defaults are added to the frame where arguments are missing.  1372   1373         if parameters and function_defaults is not None:  1374   1375             # Visit each default and set any missing arguments. Where keyword  1376             # arguments have been used, the defaults must be inspected and, if  1377             # necessary, inserted into gaps in the argument list.  1378   1379             for i, (argname, default) in enumerate(function_defaults):  1380                 argnum = parameters.index(argname)  1381                 if not args[argnum + reserved_args]:  1382                     args[argnum + reserved_args] = "__GETDEFAULT(%s, %d)" % (target_structure, i)  1383   1384         elif known_parameters:  1385   1386             # No specific parameter details are provided, but no keyword  1387             # arguments are used. Thus, defaults can be supplied using position  1388             # information only.  1389   1390             i = len(n.args)  1391             pos = i - (num_parameters - num_defaults)  1392             while i < num_parameters:  1393                 args[i + reserved_args] = "__GETDEFAULT(%s.value, %d)" % (target_var, pos)  1394                 i += 1  1395                 pos += 1  1396   1397         # Test for missing arguments.  1398   1399         if None in args:  1400             raise TranslateError("Not all arguments supplied.",  1401                                  self.get_namespace_path(), n)  1402   1403         # Encode the arguments.  1404   1405         # Where literal instantiation is occurring, add an argument indicating  1406         # the number of values. The stack and context are excluded.  1407   1408         if literal_instantiation:  1409             argstr = "%d, %s" % (len(args) - reserved_args, ", ".join(args[reserved_args:]))  1410         else:  1411             argstr = ", ".join(args)  1412   1413         kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0"  1414         kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0"  1415   1416         # First, the invocation expression is presented.  1417   1418         stages = []  1419         emit = stages.append  1420   1421         # Assign and yield any stored target.  1422         # The context may be set in the expression.  1423   1424         if need_target_stored:  1425             emit("%s = %s" % (target_var, expr))  1426             target_expr = target_var  1427   1428         # Otherwise, retain the expression for later use.  1429   1430         else:  1431             target_expr = str(expr)  1432   1433         # Any specific callable is then obtained for invocation.  1434   1435         if target:  1436   1437             # An expression involving a test of the accessor providing the target.  1438             # This must be emitted in order to perform the test.  1439   1440             if tests_accessor:  1441                 emit(str(expr))  1442   1443             emit(target)  1444   1445         # Methods accessed via unidentified accessors are obtained for  1446         # invocation.  1447   1448         elif function:  1449             if context_required:  1450   1451                 # Avoid further context testing if appropriate.  1452   1453                 if have_access_context and context_verified:  1454                     emit("__get_function_member(%s)" % target_expr)  1455   1456                 # Otherwise, test the context for the function/method.  1457   1458                 else:  1459                     emit("__get_function(%s, %s)" % (context_arg, target_expr))  1460             else:  1461                 emit("_get_function_member(%s)" % target_expr)  1462   1463         # With known parameters, the target can be tested.  1464   1465         elif known_parameters:  1466             if self.always_callable(refs):  1467                 if context_verified:  1468                     emit("__get_function_member(%s)" % target_expr)  1469                 else:  1470                     emit("__get_function(%s, %s)" % (context_arg, target_expr))  1471             else:  1472                 emit("__check_and_get_function(%s, %s)" % (context_arg, target_expr))  1473   1474         # With a known target, the function is obtained directly and called.  1475         # By putting the invocation at the end of the final element in the  1476         # instruction sequence (the stages), the result becomes the result of  1477         # the sequence. Moreover, the parameters become part of the sequence  1478         # and thereby participate in a guaranteed evaluation order.  1479   1480         if target or function or known_parameters:  1481             stages[-1] += "(%s)" % argstr  1482             if instantiation:  1483                 return InstantiationResult(instantiation, stages)  1484             else:  1485                 return InvocationResult(stages)  1486   1487         # With unknown targets, the generic invocation function is applied to  1488         # the callable and argument collections.  1489   1490         else:  1491             emit("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % (  1492                 target_expr,  1493                 self.always_callable(refs) and 1 or 0,  1494                 len(kwargs), kwcodestr, kwargstr,  1495                 len(args), "__ARGS(%s)" % argstr))  1496             return InvocationResult(stages)  1497   1498     def next_target(self):  1499   1500         "Allocate the next function target storage."  1501   1502         self.function_target += 1  1503         self.max_function_target = max(self.function_target, self.max_function_target)  1504   1505     def next_context(self):  1506   1507         "Allocate the next context value storage."  1508   1509         self.context_index += 1  1510         self.max_context_index = max(self.context_index, self.max_context_index)  1511   1512     def next_accessor(self):  1513   1514         "Allocate the next accessor value storage."  1515   1516         self.accessor_index += 1  1517         self.max_accessor_index = max(self.accessor_index, self.max_accessor_index)  1518   1519     def always_callable(self, refs):  1520   1521         "Determine whether all 'refs' are callable."  1522   1523         if not refs:  1524             return False  1525   1526         for ref in refs:  1527             if not ref.has_kind("<function>") and not self.importer.get_attributes(ref, "__fn__"):  1528                 return False  1529   1530         return True  1531   1532     def need_default_arguments(self, objpath, nargs):  1533   1534         """  1535         Return whether any default arguments are needed when invoking the object  1536         given by 'objpath'.  1537         """  1538   1539         parameters = self.importer.function_parameters.get(objpath)  1540         return nargs < len(parameters)  1541   1542     def uses_keyword_arguments(self, n):  1543   1544         "Return whether invocation node 'n' uses keyword arguments."  1545   1546         for arg in enumerate(n.args):  1547             if isinstance(arg, compiler.ast.Keyword):  1548                 return True  1549   1550         return False  1551   1552     def get_attributes_for_attrname(self, attrname):  1553   1554         "Return a set of all attributes exposed by 'attrname'."  1555   1556         usage = [(attrname, True, False)]  1557         class_types = self.deducer.get_class_types_for_usage(usage)  1558         instance_types = self.deducer.get_instance_types_for_usage(usage)  1559         module_types = self.deducer.get_module_types_for_usage(usage)  1560         attrs = set()  1561   1562         for ref in combine_types(class_types, instance_types, module_types):  1563             attrs.update(self.importer.get_attributes(ref, attrname))  1564   1565         return attrs  1566   1567     def process_lambda_node(self, n):  1568   1569         "Process the given lambda node 'n'."  1570   1571         name = self.get_lambda_name()  1572         function_name = self.get_object_path(name)  1573         instance_name = "__get_accessor(%d)" % self.accessor_index  1574   1575         defaults = self.process_function_defaults(n, name, function_name, instance_name)  1576   1577         # Without defaults, produce an attribute referring to the function.  1578   1579         if not defaults:  1580             return make_expression("__ATTRVALUE(&%s)" % encode_path(function_name))  1581   1582         # With defaults, copy the function structure and set the defaults on the  1583         # copy.  1584   1585         else:  1586             self.record_temp("__tmp_values")  1587             return make_expression("""\  1588 (__set_accessor(%d, __ATTRVALUE(__COPY(&%s, sizeof(%s)))),  1589  %s,  1590  __get_accessor(%d))""" % (  1591                 self.accessor_index,  1592                 encode_path(function_name),  1593                 encode_symbol("obj", function_name),  1594                 ", ".join(defaults),  1595                 self.accessor_index))  1596   1597     def process_logical_node(self, n):  1598   1599         "Process the given operator node 'n'."  1600   1601         self.record_temp("__tmp_result")  1602   1603         conjunction = isinstance(n, compiler.ast.And)  1604         results = []  1605   1606         for node in n.nodes:  1607             results.append(self.process_structure_node(node))  1608   1609         return LogicalOperationResult(results, conjunction)  1610   1611     def process_name_node(self, n, expr=None):  1612   1613         "Process the given name node 'n' with the optional assignment 'expr'."  1614   1615         # Determine whether the name refers to a static external entity.  1616   1617         if n.name in predefined_constants:  1618             return PredefinedConstantRef(n.name, expr)  1619   1620         # Convert literal references, operator function names, and print  1621         # function names to references.  1622   1623         elif n.name.startswith("$L") or n.name.startswith("$op") or \  1624              n.name.startswith("$seq") or n.name.startswith("$print"):  1625   1626             ref, paths = self.importer.get_module(self.name).special[n.name]  1627             return TrResolvedNameRef(n.name, ref)  1628   1629         # Get the appropriate name for the name reference, using the same method  1630         # as in the inspector.  1631   1632         path = self.get_namespace_path()  1633         objpath = self.get_object_path(n.name)  1634   1635         # Determine any assigned globals.  1636   1637         globals = self.importer.get_module(self.name).scope_globals.get(path)  1638   1639         # Explicitly declared globals.  1640   1641         if globals and n.name in globals:  1642             objpath = self.get_global_path(n.name)  1643             is_global = True  1644   1645         # Implicitly referenced globals in functions.  1646   1647         elif self.in_function:  1648             is_global = n.name not in self.importer.function_locals[path]  1649   1650         # Implicitly referenced globals elsewhere.  1651   1652         else:  1653             namespace = self.importer.identify(path)  1654             is_global = not self.importer.get_attributes(namespace, n.name)  1655   1656         # Get the static identity of the name.  1657   1658         ref = self.importer.identify(objpath)  1659         if ref and not ref.get_name():  1660             ref = ref.alias(objpath)  1661   1662         # Obtain any resolved names for non-assignment names.  1663   1664         if not expr and not ref and self.in_function:  1665             locals = self.importer.function_locals.get(path)  1666             ref = locals and locals.get(n.name)  1667   1668         # Find any invocation or alias details.  1669   1670         name = self.get_name_for_tracking(n.name, is_global=is_global)  1671         location = not expr and self.get_access_location(name) or None  1672   1673         # Mark any local assignments as volatile in exception blocks.  1674   1675         if expr and self.in_function and not is_global and self.in_try_except:  1676             self.make_volatile(n.name)  1677   1678         # Qualified names are used for resolved static references or for  1679         # static namespace members. The reference should be configured to return  1680         # such names.  1681   1682         name_ref = TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global,  1683                                      location=location)  1684         return not expr and self.get_aliases(name_ref) or name_ref  1685   1686     def get_aliases(self, name_ref):  1687   1688         "Return alias references for the given 'name_ref'."  1689   1690         location = name_ref.access_location()  1691         accessor_locations = self.deducer.access_index.get(location)  1692   1693         if not accessor_locations:  1694             return None  1695   1696         refs = set()  1697   1698         for accessor_location in accessor_locations:  1699             alias_refs = self.deducer.referenced_objects.get(accessor_location)  1700             if alias_refs:  1701                 refs.update(alias_refs)  1702   1703         if refs:  1704             return AliasResult(name_ref, refs, location)  1705         else:  1706             return None  1707   1708     def make_volatile(self, name):  1709   1710         "Record 'name' as volatile in the current namespace."  1711   1712         self.volatile_locals.add(name)  1713   1714     def process_not_node(self, n):  1715   1716         "Process the given operator node 'n'."  1717   1718         return self.make_negation(self.process_structure_node(n.expr))  1719   1720     def process_raise_node(self, n):  1721   1722         "Process the given raise node 'n'."  1723   1724         # NOTE: Determine which raise statement variants should be permitted.  1725   1726         if n.expr1:  1727   1728             # Names with accompanying arguments are treated like invocations.  1729   1730             if n.expr2:  1731                 call = compiler.ast.CallFunc(n.expr1, [n.expr2])  1732                 exc = self.process_structure_node(call)  1733                 self.writestmt("__Raise(%s);" % exc)  1734   1735             # Raise instances, testing the kind at run-time if necessary and  1736             # instantiating any non-instance.  1737   1738             else:  1739                 exc = self.process_structure_node(n.expr1)  1740   1741                 if isinstance(exc, TrInstanceRef):  1742                     self.writestmt("__Raise(%s);" % exc)  1743                 else:  1744                     self.writestmt("__Raise(__ensure_instance(__stack, %s));" % exc)  1745         else:  1746             self.writestmt("__Throw(__tmp_exc);")  1747   1748     def process_return_node(self, n):  1749   1750         "Process the given return node 'n'."  1751   1752         expr = self.process_structure_node(n.value) or PredefinedConstantRef("None")  1753         if self.in_try_finally or self.in_try_except:  1754             self.writestmt("__Return(%s);" % expr)  1755         else:  1756             self.writestmt("return %s;" % expr)  1757   1758         return ReturnRef()  1759   1760     def process_try_node(self, n):  1761   1762         """  1763         Process the given "try...except" node 'n'.  1764         """  1765   1766         in_try_except = self.in_try_except  1767         self.in_try_except = True  1768   1769         # Use macros to implement exception handling.  1770   1771         self.writestmt("__Try")  1772         self.writeline("{")  1773         self.indent += 1  1774         self.process_structure_node(n.body)  1775   1776         # Put the else statement in another try block that handles any raised  1777         # exceptions and converts them to exceptions that will not be handled by  1778         # the main handling block.  1779   1780         if n.else_:  1781             self.writestmt("__Try")  1782             self.writeline("{")  1783             self.indent += 1  1784             self.process_structure_node(n.else_)  1785             self.indent -= 1  1786             self.writeline("}")  1787             self.writeline("__Catch (__tmp_exc)")  1788             self.writeline("{")  1789             self.indent += 1  1790             self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);")  1791             self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);")  1792             self.indent -= 1  1793             self.writeline("}")  1794   1795         # Complete the try block and enter the finally block, if appropriate.  1796   1797         if self.in_try_finally:  1798             self.writestmt("__Complete;")  1799   1800         self.indent -= 1  1801         self.writeline("}")  1802   1803         self.in_try_except = in_try_except  1804   1805         # Handlers are tests within a common handler block.  1806   1807         self.writeline("__Catch (__tmp_exc)")  1808         self.writeline("{")  1809         self.indent += 1  1810   1811         # Introduce an if statement to handle the completion of a try block.  1812   1813         self.process_try_completion()  1814   1815         # Handle exceptions in else blocks converted to __RaiseElse, converting  1816         # them back to normal exceptions.  1817   1818         if n.else_:  1819             self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);")  1820   1821         # Exception handling.  1822   1823         for name, var, handler in n.handlers:  1824   1825             # Test for specific exceptions.  1826   1827             if name is not None:  1828                 name_ref = self.process_structure_node(name)  1829                 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref)  1830             else:  1831                 self.writeline("else if (1)")  1832   1833             self.writeline("{")  1834             self.indent += 1  1835   1836             # Establish the local for the handler.  1837   1838             if var is not None:  1839                 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg")))  1840   1841             if handler is not None:  1842                 self.process_structure_node(handler)  1843   1844             self.indent -= 1  1845             self.writeline("}")  1846   1847         # Re-raise unhandled exceptions.  1848   1849         self.writeline("else __Throw(__tmp_exc);")  1850   1851         # End the handler block.  1852   1853         self.indent -= 1  1854         self.writeline("}")  1855         print >>self.out  1856   1857     def process_try_finally_node(self, n):  1858   1859         """  1860         Process the given "try...finally" node 'n'.  1861         """  1862   1863         in_try_finally = self.in_try_finally  1864         self.in_try_finally = True  1865   1866         # Use macros to implement exception handling.  1867   1868         self.writestmt("__Try")  1869         self.writeline("{")  1870         self.indent += 1  1871         self.process_structure_node(n.body)  1872         self.indent -= 1  1873         self.writeline("}")  1874   1875         self.in_try_finally = in_try_finally  1876   1877         # Finally clauses handle special exceptions.  1878   1879         self.writeline("__Catch (__tmp_exc)")  1880         self.writeline("{")  1881         self.indent += 1  1882         self.process_structure_node(n.final)  1883   1884         # Introduce an if statement to handle the completion of a try block.  1885   1886         self.process_try_completion()  1887         self.writeline("else __Throw(__tmp_exc);")  1888   1889         self.indent -= 1  1890         self.writeline("}")  1891         print >>self.out  1892   1893     def process_try_completion(self):  1894   1895         "Generate a test for the completion of a try block."  1896   1897         self.writestmt("if (__tmp_exc.completing)")  1898         self.writeline("{")  1899         self.indent += 1  1900   1901         # Do not return anything at the module level.  1902   1903         if self.get_namespace_path() != self.name:  1904   1905             # Only use the normal return statement if no surrounding try blocks  1906             # apply.  1907   1908             if not self.in_try_finally and not self.in_try_except:  1909                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;")  1910             else:  1911                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);")  1912   1913         self.indent -= 1  1914         self.writeline("}")  1915   1916     def process_while_node(self, n):  1917   1918         "Process the given while node 'n'."  1919   1920         self.writeline("while (1)")  1921         self.writeline("{")  1922         self.indent += 1  1923         test = self.process_structure_node(n.test)  1924   1925         # Emit the loop termination condition unless "while <true value>" is  1926         # indicated.  1927   1928         if not (isinstance(test, PredefinedConstantRef) and test.value):  1929   1930             # Emit a negated test of the continuation condition.  1931   1932             self.start_if(True, self.make_negation(test))  1933             if n.else_:  1934                 self.process_structure_node(n.else_)  1935             self.writestmt("break;")  1936             self.end_if()  1937   1938         in_conditional = self.in_conditional  1939         self.in_conditional = True  1940         self.process_structure_node(n.body)  1941         self.in_conditional = in_conditional  1942   1943         self.indent -= 1  1944         self.writeline("}")  1945         print >>self.out  1946   1947     # Special variable usage.  1948   1949     def get_temp_path(self):  1950   1951         """  1952         Return the appropriate namespace path for temporary names in the current  1953         namespace.  1954         """  1955   1956         if self.in_function:  1957             return self.get_namespace_path()  1958         else:  1959             return self.name  1960   1961     def record_temp(self, name):  1962   1963         """  1964         Record the use of the temporary 'name' in the current namespace. At the  1965         class or module level, the temporary name is associated with the module,  1966         since the variable will then be allocated in the module's own main  1967         program.  1968         """  1969   1970         path = self.get_temp_path()  1971   1972         init_item(self.temp_usage, path, list)  1973         self.temp_usage[path].append(name)  1974   1975     def remove_temps(self, names):  1976   1977         """  1978         Remove 'names' from temporary storage allocations, each instance  1979         removing each request for storage.  1980         """  1981   1982         path = self.get_temp_path()  1983   1984         for name in names:  1985             if self.uses_temp(path, name):  1986                 self.temp_usage[path].remove(name)  1987   1988     def uses_temp(self, path, name):  1989   1990         """  1991         Return whether the given namespace 'path' employs a temporary variable  1992         with the given 'name'. Note that 'path' should only be a module or a  1993         function or method, not a class.  1994         """  1995   1996         return self.temp_usage.has_key(path) and name in self.temp_usage[path]  1997   1998     def make_negation(self, expr):  1999   2000         "Return a negated form of 'expr'."  2001   2002         result = NegationResult(expr)  2003   2004         # Negation discards the temporary results of its operand.  2005   2006         temps = expr.discards_temporary()  2007         if temps:  2008             self.remove_temps(temps)  2009   2010         return result  2011   2012     # Output generation.  2013   2014     def start_output(self):  2015   2016         "Write the declarations at the top of each source file."  2017   2018         print >>self.out, """\  2019 #include "types.h"  2020 #include "exceptions.h"  2021 #include "ops.h"  2022 #include "progconsts.h"  2023 #include "progops.h"  2024 #include "progtypes.h"  2025 #include "main.h"  2026 """  2027   2028     def start_unit(self):  2029   2030         "Record output within a generated function for later use."  2031   2032         self.out = StringIO()  2033   2034     def end_unit(self):  2035   2036         "Restore the output stream."  2037   2038         out = self.out  2039         self.out = self.out_toplevel  2040         return out  2041   2042     def flush_unit(self, name, out):  2043   2044         "Add declarations and generated code."  2045   2046         self.write_temporaries(name)  2047         print >>self.out  2048         out.seek(0)  2049         self.out.write(out.read())  2050   2051     def start_module(self):  2052   2053         "Write the start of each module's main function."  2054   2055         print >>self.out, "void __main_%s(__attr __stack)" % encode_path(self.name)  2056         print >>self.out, "{"  2057         self.indent += 1  2058   2059         # Define temporary variables, excluded from the module structure itself.  2060   2061         tempnames = []  2062   2063         for n in self.importer.all_module_attrs[self.name]:  2064             if n.startswith("$t"):  2065                 tempnames.append(encode_path(n))  2066   2067         if tempnames:  2068             tempnames.sort()  2069             self.writeline("__attr %s;" % ", ".join(tempnames))  2070   2071         self.start_unit()  2072   2073     def end_module(self):  2074   2075         "End each module by closing its main function."  2076   2077         out = self.end_unit()  2078         self.flush_unit(self.name, out)  2079   2080         self.indent -= 1  2081         print >>self.out, "}"  2082   2083     def start_function(self, name):  2084   2085         "Start the function having the given 'name'."  2086   2087         self.indent += 1  2088   2089         self.start_unit()  2090   2091     def end_function(self, name):  2092   2093         "End the function having the given 'name'."  2094   2095         out = self.end_unit()  2096   2097         # Write the signature at the top indentation level.  2098   2099         self.indent -= 1  2100         self.write_parameters(name)  2101         print >>self.out, "{"  2102   2103         # Obtain local names from parameters.  2104   2105         parameters = self.importer.function_parameters[name]  2106         locals = self.importer.function_locals[name].keys()  2107         names = []  2108         volatile_names = []  2109   2110         for n in locals:  2111   2112             # Filter out special names and parameters. Note that self is a local  2113             # regardless of whether it originally appeared in the parameters or  2114             # not.  2115   2116             if n.startswith("$l") or n in parameters or n == "self":  2117                 continue  2118             if n in self.volatile_locals:  2119                 volatile_names.append(encode_path(n))  2120             else:  2121                 names.append(encode_path(n))  2122   2123         # Emit required local names at the function indentation level.  2124   2125         self.indent += 1  2126   2127         if names:  2128             names.sort()  2129             self.writeline("__attr %s;" % ", ".join(names))  2130   2131         if volatile_names:  2132             volatile_names.sort()  2133             self.writeline("volatile __attr %s;" % ", ".join(volatile_names))  2134   2135         self.flush_unit(name, out)  2136   2137         self.indent -= 1  2138         print >>self.out, "}"  2139         print >>self.out  2140   2141     def write_parameters(self, name):  2142   2143         """  2144         For the function having the given 'name', write definitions of  2145         parameters found in the arguments array.  2146         """  2147   2148         l = []  2149   2150         # Generate the parallel value stack reference.  2151   2152         l.append("__attr __stack")  2153   2154         # Generate any self reference.  2155   2156         if self.is_method(name):  2157             l.append("__attr self")  2158         else:  2159             l.append("__attr __self")  2160   2161         # Generate aliases for the parameters.  2162   2163         for parameter in self.importer.function_parameters[name]:  2164             l.append("%s__attr %s" % (  2165                 parameter in self.volatile_locals and "volatile " or "",  2166                 encode_path(parameter)))  2167   2168         self.writeline("__attr %s(%s)" % (  2169             encode_function_pointer(name), ", ".join(l)))  2170   2171     def write_temporaries(self, name):  2172   2173         "Write temporary storage employed by 'name'."  2174   2175         # Provide space for the recorded number of temporary variables.  2176   2177         if self.uses_temp(name, "__tmp_targets"):  2178             self.writeline("__attr __tmp_targets[%d];" % self.max_function_target)  2179   2180         if self.uses_temp(name, "__tmp_contexts"):  2181             self.writeline("__attr __tmp_contexts[%d];" % self.max_context_index)  2182   2183         if self.uses_temp(name, "__tmp_values"):  2184             self.writeline("__attr __tmp_values[%d];" % self.max_accessor_index)  2185   2186         # Add temporary variable usage details.  2187   2188         if self.uses_temp(name, "__tmp_private_context"):  2189             self.writeline("__attr __tmp_private_context;")  2190         if self.uses_temp(name, "__tmp_target_value"):  2191             self.writeline("__attr __tmp_target_value;")  2192         if self.uses_temp(name, "__tmp_result"):  2193             self.writeline("__attr __tmp_result;")  2194   2195         module = self.importer.get_module(self.name)  2196   2197         if name in module.exception_namespaces:  2198             self.writeline("__exc __tmp_exc;")  2199   2200     def start_if(self, first, test_ref):  2201         statement = "%sif" % (not first and "else " or "")  2202   2203         # Consume logical results directly.  2204   2205         if isinstance(test_ref, LogicalResult):  2206             self.writeline("%s %s" % (statement, test_ref.apply_test()))  2207             temps = test_ref.discards_temporary()  2208             if temps:  2209                 self.remove_temps(temps)  2210         else:  2211             self.writeline("%s (__BOOL(%s))" % (statement, test_ref))  2212   2213         self.writeline("{")  2214         self.indent += 1  2215   2216     def end_if(self):  2217         self.indent -= 1  2218         self.writeline("}")  2219   2220     def start_else(self):  2221         self.writeline("else")  2222         self.writeline("{")  2223         self.indent += 1  2224   2225     def end_else(self):  2226         self.indent -= 1  2227         self.writeline("}")  2228   2229     def statement(self, expr):  2230         s = str(expr)  2231         if s:  2232             self.writestmt("%s;" % s)  2233   2234     def statements(self, results):  2235         for result in results:  2236             self.statement(result)  2237   2238     def writeline(self, s):  2239         print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1))  2240   2241     def writestmt(self, s):  2242         self.writeline(s)  2243   2244     def write_comment(self, s):  2245         self.writestmt("/* %s */" % s)  2246   2247     def pad(self, extra=0):  2248         return (self.indent + extra) * self.tabstop  2249   2250     def indenttext(self, s, levels):  2251         lines = s.split("\n")  2252         out = [lines[0]]  2253         for line in lines[1:]:  2254             out.append(levels * self.tabstop + line)  2255             if line.endswith("("):  2256                 levels += 1  2257             elif line.startswith(")"):  2258                 levels -= 1  2259         return "\n".join(out)  2260   2261 # vim: tabstop=4 expandtab shiftwidth=4