Lichen

translator.py

957:c086e5c5db75
2 months ago Paul Boddie Added reserved argument count to the invocation generation code.
     1 #!/usr/bin/env python     2      3 """     4 Translate programs.     5      6 Copyright (C) 2015, 2016, 2017, 2018 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. Where it would be unused, it may be  1285         # 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         args = [context_arg]  1296         reserved_args = 1  1297   1298         # Complete the array with null values, permitting tests for a complete  1299         # set of arguments.  1300   1301         args += [None] * (num_parameters is None and len(n.args) or num_parameters is not None and num_parameters or 0)  1302         kwcodes = []  1303         kwargs = []  1304   1305         # Any invocations in the arguments will store target details in a  1306         # different location.  1307   1308         function_target = self.function_target  1309         context_index = self.context_index  1310         accessor_index = self.accessor_index  1311   1312         if need_target_stored:  1313             self.next_target()  1314   1315         if need_context_stored:  1316             self.next_context()  1317   1318         if stores_accessor:  1319             self.next_accessor()  1320   1321         in_parameter_list = self.in_parameter_list  1322         self.in_parameter_list = True  1323   1324         for i, arg in enumerate(n.args):  1325             argexpr = self.process_structure_node(arg)  1326   1327             # Store a keyword argument, either in the argument list or  1328             # in a separate keyword argument list for subsequent lookup.  1329   1330             if isinstance(arg, compiler.ast.Keyword):  1331   1332                 # With knowledge of the target, store the keyword  1333                 # argument directly.  1334   1335                 if parameters:  1336                     try:  1337                         argnum = parameters.index(arg.name)  1338                     except ValueError:  1339                         raise TranslateError("Argument %s is not recognised." % arg.name,  1340                                              self.get_namespace_path(), n)  1341                     args[argnum + reserved_args] = str(argexpr)  1342   1343                 # Otherwise, store the details in a separate collection.  1344   1345                 else:  1346                     kwargs.append(str(argexpr))  1347                     kwcodes.append("{%s, %s}" % (  1348                         encode_ppos(arg.name), encode_pcode(arg.name)))  1349   1350             # Store non-keyword arguments in the argument list, rejecting  1351             # superfluous arguments.  1352   1353             else:  1354                 try:  1355                     args[i + reserved_args] = str(argexpr)  1356                 except IndexError:  1357                     raise TranslateError("Too many arguments specified.",  1358                                          self.get_namespace_path(), n)  1359   1360         # Reference the current target again.  1361   1362         self.in_parameter_list = in_parameter_list  1363   1364         if not self.in_parameter_list:  1365             self.function_target = function_target  1366             self.context_index = context_index  1367             self.accessor_index = accessor_index  1368   1369         # Defaults are added to the frame where arguments are missing.  1370   1371         if parameters and function_defaults is not None:  1372   1373             # Visit each default and set any missing arguments. Where keyword  1374             # arguments have been used, the defaults must be inspected and, if  1375             # necessary, inserted into gaps in the argument list.  1376   1377             for i, (argname, default) in enumerate(function_defaults):  1378                 argnum = parameters.index(argname)  1379                 if not args[argnum + reserved_args]:  1380                     args[argnum + reserved_args] = "__GETDEFAULT(%s, %d)" % (target_structure, i)  1381   1382         elif known_parameters:  1383   1384             # No specific parameter details are provided, but no keyword  1385             # arguments are used. Thus, defaults can be supplied using position  1386             # information only.  1387   1388             i = len(n.args)  1389             pos = i - (num_parameters - num_defaults)  1390             while i < num_parameters:  1391                 args[i + reserved_args] = "__GETDEFAULT(%s.value, %d)" % (target_var, pos)  1392                 i += 1  1393                 pos += 1  1394   1395         # Test for missing arguments.  1396   1397         if None in args:  1398             raise TranslateError("Not all arguments supplied.",  1399                                  self.get_namespace_path(), n)  1400   1401         # Encode the arguments.  1402   1403         # Where literal instantiation is occurring, add an argument indicating  1404         # the number of values. The context is excluded.  1405   1406         if literal_instantiation:  1407             argstr = "%d, %s" % (len(args) - reserved_args, ", ".join(args[reserved_args:]))  1408         else:  1409             argstr = ", ".join(args)  1410   1411         kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0"  1412         kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0"  1413   1414         # First, the invocation expression is presented.  1415   1416         stages = []  1417         emit = stages.append  1418   1419         # Assign and yield any stored target.  1420         # The context may be set in the expression.  1421   1422         if need_target_stored:  1423             emit("%s = %s" % (target_var, expr))  1424             target_expr = target_var  1425   1426         # Otherwise, retain the expression for later use.  1427   1428         else:  1429             target_expr = str(expr)  1430   1431         # Any specific callable is then obtained for invocation.  1432   1433         if target:  1434   1435             # An expression involving a test of the accessor providing the target.  1436             # This must be emitted in order to perform the test.  1437   1438             if tests_accessor:  1439                 emit(str(expr))  1440   1441             emit(target)  1442   1443         # Methods accessed via unidentified accessors are obtained for  1444         # invocation.  1445   1446         elif function:  1447             if context_required:  1448   1449                 # Avoid further context testing if appropriate.  1450   1451                 if have_access_context and context_verified:  1452                     emit("__get_function_member(%s)" % target_expr)  1453   1454                 # Otherwise, test the context for the function/method.  1455   1456                 else:  1457                     emit("__get_function(%s, %s)" % (context_arg, target_expr))  1458             else:  1459                 emit("_get_function_member(%s)" % target_expr)  1460   1461         # With known parameters, the target can be tested.  1462   1463         elif known_parameters:  1464             if self.always_callable(refs):  1465                 if context_verified:  1466                     emit("__get_function_member(%s)" % target_expr)  1467                 else:  1468                     emit("__get_function(%s, %s)" % (context_arg, target_expr))  1469             else:  1470                 emit("__check_and_get_function(%s, %s)" % (context_arg, target_expr))  1471   1472         # With a known target, the function is obtained directly and called.  1473         # By putting the invocation at the end of the final element in the  1474         # instruction sequence (the stages), the result becomes the result of  1475         # the sequence. Moreover, the parameters become part of the sequence  1476         # and thereby participate in a guaranteed evaluation order.  1477   1478         if target or function or known_parameters:  1479             stages[-1] += "(%s)" % argstr  1480             if instantiation:  1481                 return InstantiationResult(instantiation, stages)  1482             else:  1483                 return InvocationResult(stages)  1484   1485         # With unknown targets, the generic invocation function is applied to  1486         # the callable and argument collections.  1487   1488         else:  1489             emit("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % (  1490                 target_expr,  1491                 self.always_callable(refs) and 1 or 0,  1492                 len(kwargs), kwcodestr, kwargstr,  1493                 len(args), "__ARGS(%s)" % argstr))  1494             return InvocationResult(stages)  1495   1496     def next_target(self):  1497   1498         "Allocate the next function target storage."  1499   1500         self.function_target += 1  1501         self.max_function_target = max(self.function_target, self.max_function_target)  1502   1503     def next_context(self):  1504   1505         "Allocate the next context value storage."  1506   1507         self.context_index += 1  1508         self.max_context_index = max(self.context_index, self.max_context_index)  1509   1510     def next_accessor(self):  1511   1512         "Allocate the next accessor value storage."  1513   1514         self.accessor_index += 1  1515         self.max_accessor_index = max(self.accessor_index, self.max_accessor_index)  1516   1517     def always_callable(self, refs):  1518   1519         "Determine whether all 'refs' are callable."  1520   1521         if not refs:  1522             return False  1523   1524         for ref in refs:  1525             if not ref.has_kind("<function>") and not self.importer.get_attributes(ref, "__fn__"):  1526                 return False  1527   1528         return True  1529   1530     def need_default_arguments(self, objpath, nargs):  1531   1532         """  1533         Return whether any default arguments are needed when invoking the object  1534         given by 'objpath'.  1535         """  1536   1537         parameters = self.importer.function_parameters.get(objpath)  1538         return nargs < len(parameters)  1539   1540     def uses_keyword_arguments(self, n):  1541   1542         "Return whether invocation node 'n' uses keyword arguments."  1543   1544         for arg in enumerate(n.args):  1545             if isinstance(arg, compiler.ast.Keyword):  1546                 return True  1547   1548         return False  1549   1550     def get_attributes_for_attrname(self, attrname):  1551   1552         "Return a set of all attributes exposed by 'attrname'."  1553   1554         usage = [(attrname, True, False)]  1555         class_types = self.deducer.get_class_types_for_usage(usage)  1556         instance_types = self.deducer.get_instance_types_for_usage(usage)  1557         module_types = self.deducer.get_module_types_for_usage(usage)  1558         attrs = set()  1559   1560         for ref in combine_types(class_types, instance_types, module_types):  1561             attrs.update(self.importer.get_attributes(ref, attrname))  1562   1563         return attrs  1564   1565     def process_lambda_node(self, n):  1566   1567         "Process the given lambda node 'n'."  1568   1569         name = self.get_lambda_name()  1570         function_name = self.get_object_path(name)  1571         instance_name = "__get_accessor(%d)" % self.accessor_index  1572   1573         defaults = self.process_function_defaults(n, name, function_name, instance_name)  1574   1575         # Without defaults, produce an attribute referring to the function.  1576   1577         if not defaults:  1578             return make_expression("__ATTRVALUE(&%s)" % encode_path(function_name))  1579   1580         # With defaults, copy the function structure and set the defaults on the  1581         # copy.  1582   1583         else:  1584             self.record_temp("__tmp_values")  1585             return make_expression("""\  1586 (__set_accessor(%d, __ATTRVALUE(__COPY(&%s, sizeof(%s)))),  1587  %s,  1588  __get_accessor(%d))""" % (  1589                 self.accessor_index,  1590                 encode_path(function_name),  1591                 encode_symbol("obj", function_name),  1592                 ", ".join(defaults),  1593                 self.accessor_index))  1594   1595     def process_logical_node(self, n):  1596   1597         "Process the given operator node 'n'."  1598   1599         self.record_temp("__tmp_result")  1600   1601         conjunction = isinstance(n, compiler.ast.And)  1602         results = []  1603   1604         for node in n.nodes:  1605             results.append(self.process_structure_node(node))  1606   1607         return LogicalOperationResult(results, conjunction)  1608   1609     def process_name_node(self, n, expr=None):  1610   1611         "Process the given name node 'n' with the optional assignment 'expr'."  1612   1613         # Determine whether the name refers to a static external entity.  1614   1615         if n.name in predefined_constants:  1616             return PredefinedConstantRef(n.name, expr)  1617   1618         # Convert literal references, operator function names, and print  1619         # function names to references.  1620   1621         elif n.name.startswith("$L") or n.name.startswith("$op") or \  1622              n.name.startswith("$seq") or n.name.startswith("$print"):  1623   1624             ref, paths = self.importer.get_module(self.name).special[n.name]  1625             return TrResolvedNameRef(n.name, ref)  1626   1627         # Get the appropriate name for the name reference, using the same method  1628         # as in the inspector.  1629   1630         path = self.get_namespace_path()  1631         objpath = self.get_object_path(n.name)  1632   1633         # Determine any assigned globals.  1634   1635         globals = self.importer.get_module(self.name).scope_globals.get(path)  1636   1637         # Explicitly declared globals.  1638   1639         if globals and n.name in globals:  1640             objpath = self.get_global_path(n.name)  1641             is_global = True  1642   1643         # Implicitly referenced globals in functions.  1644   1645         elif self.in_function:  1646             is_global = n.name not in self.importer.function_locals[path]  1647   1648         # Implicitly referenced globals elsewhere.  1649   1650         else:  1651             namespace = self.importer.identify(path)  1652             is_global = not self.importer.get_attributes(namespace, n.name)  1653   1654         # Get the static identity of the name.  1655   1656         ref = self.importer.identify(objpath)  1657         if ref and not ref.get_name():  1658             ref = ref.alias(objpath)  1659   1660         # Obtain any resolved names for non-assignment names.  1661   1662         if not expr and not ref and self.in_function:  1663             locals = self.importer.function_locals.get(path)  1664             ref = locals and locals.get(n.name)  1665   1666         # Find any invocation or alias details.  1667   1668         name = self.get_name_for_tracking(n.name, is_global=is_global)  1669         location = not expr and self.get_access_location(name) or None  1670   1671         # Mark any local assignments as volatile in exception blocks.  1672   1673         if expr and self.in_function and not is_global and self.in_try_except:  1674             self.make_volatile(n.name)  1675   1676         # Qualified names are used for resolved static references or for  1677         # static namespace members. The reference should be configured to return  1678         # such names.  1679   1680         name_ref = TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global,  1681                                      location=location)  1682         return not expr and self.get_aliases(name_ref) or name_ref  1683   1684     def get_aliases(self, name_ref):  1685   1686         "Return alias references for the given 'name_ref'."  1687   1688         location = name_ref.access_location()  1689         accessor_locations = self.deducer.access_index.get(location)  1690   1691         if not accessor_locations:  1692             return None  1693   1694         refs = set()  1695   1696         for accessor_location in accessor_locations:  1697             alias_refs = self.deducer.referenced_objects.get(accessor_location)  1698             if alias_refs:  1699                 refs.update(alias_refs)  1700   1701         if refs:  1702             return AliasResult(name_ref, refs, location)  1703         else:  1704             return None  1705   1706     def make_volatile(self, name):  1707   1708         "Record 'name' as volatile in the current namespace."  1709   1710         self.volatile_locals.add(name)  1711   1712     def process_not_node(self, n):  1713   1714         "Process the given operator node 'n'."  1715   1716         return self.make_negation(self.process_structure_node(n.expr))  1717   1718     def process_raise_node(self, n):  1719   1720         "Process the given raise node 'n'."  1721   1722         # NOTE: Determine which raise statement variants should be permitted.  1723   1724         if n.expr1:  1725   1726             # Names with accompanying arguments are treated like invocations.  1727   1728             if n.expr2:  1729                 call = compiler.ast.CallFunc(n.expr1, [n.expr2])  1730                 exc = self.process_structure_node(call)  1731                 self.writestmt("__Raise(%s);" % exc)  1732   1733             # Raise instances, testing the kind at run-time if necessary and  1734             # instantiating any non-instance.  1735   1736             else:  1737                 exc = self.process_structure_node(n.expr1)  1738   1739                 if isinstance(exc, TrInstanceRef):  1740                     self.writestmt("__Raise(%s);" % exc)  1741                 else:  1742                     self.writestmt("__Raise(__ensure_instance(%s));" % exc)  1743         else:  1744             self.writestmt("__Throw(__tmp_exc);")  1745   1746     def process_return_node(self, n):  1747   1748         "Process the given return node 'n'."  1749   1750         expr = self.process_structure_node(n.value) or PredefinedConstantRef("None")  1751         if self.in_try_finally or self.in_try_except:  1752             self.writestmt("__Return(%s);" % expr)  1753         else:  1754             self.writestmt("return %s;" % expr)  1755   1756         return ReturnRef()  1757   1758     def process_try_node(self, n):  1759   1760         """  1761         Process the given "try...except" node 'n'.  1762         """  1763   1764         in_try_except = self.in_try_except  1765         self.in_try_except = True  1766   1767         # Use macros to implement exception handling.  1768   1769         self.writestmt("__Try")  1770         self.writeline("{")  1771         self.indent += 1  1772         self.process_structure_node(n.body)  1773   1774         # Put the else statement in another try block that handles any raised  1775         # exceptions and converts them to exceptions that will not be handled by  1776         # the main handling block.  1777   1778         if n.else_:  1779             self.writestmt("__Try")  1780             self.writeline("{")  1781             self.indent += 1  1782             self.process_structure_node(n.else_)  1783             self.indent -= 1  1784             self.writeline("}")  1785             self.writeline("__Catch (__tmp_exc)")  1786             self.writeline("{")  1787             self.indent += 1  1788             self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);")  1789             self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);")  1790             self.indent -= 1  1791             self.writeline("}")  1792   1793         # Complete the try block and enter the finally block, if appropriate.  1794   1795         if self.in_try_finally:  1796             self.writestmt("__Complete;")  1797   1798         self.indent -= 1  1799         self.writeline("}")  1800   1801         self.in_try_except = in_try_except  1802   1803         # Handlers are tests within a common handler block.  1804   1805         self.writeline("__Catch (__tmp_exc)")  1806         self.writeline("{")  1807         self.indent += 1  1808   1809         # Introduce an if statement to handle the completion of a try block.  1810   1811         self.process_try_completion()  1812   1813         # Handle exceptions in else blocks converted to __RaiseElse, converting  1814         # them back to normal exceptions.  1815   1816         if n.else_:  1817             self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);")  1818   1819         # Exception handling.  1820   1821         for name, var, handler in n.handlers:  1822   1823             # Test for specific exceptions.  1824   1825             if name is not None:  1826                 name_ref = self.process_structure_node(name)  1827                 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref)  1828             else:  1829                 self.writeline("else if (1)")  1830   1831             self.writeline("{")  1832             self.indent += 1  1833   1834             # Establish the local for the handler.  1835   1836             if var is not None:  1837                 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg")))  1838   1839             if handler is not None:  1840                 self.process_structure_node(handler)  1841   1842             self.indent -= 1  1843             self.writeline("}")  1844   1845         # Re-raise unhandled exceptions.  1846   1847         self.writeline("else __Throw(__tmp_exc);")  1848   1849         # End the handler block.  1850   1851         self.indent -= 1  1852         self.writeline("}")  1853         print >>self.out  1854   1855     def process_try_finally_node(self, n):  1856   1857         """  1858         Process the given "try...finally" node 'n'.  1859         """  1860   1861         in_try_finally = self.in_try_finally  1862         self.in_try_finally = True  1863   1864         # Use macros to implement exception handling.  1865   1866         self.writestmt("__Try")  1867         self.writeline("{")  1868         self.indent += 1  1869         self.process_structure_node(n.body)  1870         self.indent -= 1  1871         self.writeline("}")  1872   1873         self.in_try_finally = in_try_finally  1874   1875         # Finally clauses handle special exceptions.  1876   1877         self.writeline("__Catch (__tmp_exc)")  1878         self.writeline("{")  1879         self.indent += 1  1880         self.process_structure_node(n.final)  1881   1882         # Introduce an if statement to handle the completion of a try block.  1883   1884         self.process_try_completion()  1885         self.writeline("else __Throw(__tmp_exc);")  1886   1887         self.indent -= 1  1888         self.writeline("}")  1889         print >>self.out  1890   1891     def process_try_completion(self):  1892   1893         "Generate a test for the completion of a try block."  1894   1895         self.writestmt("if (__tmp_exc.completing)")  1896         self.writeline("{")  1897         self.indent += 1  1898   1899         # Do not return anything at the module level.  1900   1901         if self.get_namespace_path() != self.name:  1902   1903             # Only use the normal return statement if no surrounding try blocks  1904             # apply.  1905   1906             if not self.in_try_finally and not self.in_try_except:  1907                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;")  1908             else:  1909                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);")  1910   1911         self.indent -= 1  1912         self.writeline("}")  1913   1914     def process_while_node(self, n):  1915   1916         "Process the given while node 'n'."  1917   1918         self.writeline("while (1)")  1919         self.writeline("{")  1920         self.indent += 1  1921         test = self.process_structure_node(n.test)  1922   1923         # Emit the loop termination condition unless "while <true value>" is  1924         # indicated.  1925   1926         if not (isinstance(test, PredefinedConstantRef) and test.value):  1927   1928             # Emit a negated test of the continuation condition.  1929   1930             self.start_if(True, self.make_negation(test))  1931             if n.else_:  1932                 self.process_structure_node(n.else_)  1933             self.writestmt("break;")  1934             self.end_if()  1935   1936         in_conditional = self.in_conditional  1937         self.in_conditional = True  1938         self.process_structure_node(n.body)  1939         self.in_conditional = in_conditional  1940   1941         self.indent -= 1  1942         self.writeline("}")  1943         print >>self.out  1944   1945     # Special variable usage.  1946   1947     def get_temp_path(self):  1948   1949         """  1950         Return the appropriate namespace path for temporary names in the current  1951         namespace.  1952         """  1953   1954         if self.in_function:  1955             return self.get_namespace_path()  1956         else:  1957             return self.name  1958   1959     def record_temp(self, name):  1960   1961         """  1962         Record the use of the temporary 'name' in the current namespace. At the  1963         class or module level, the temporary name is associated with the module,  1964         since the variable will then be allocated in the module's own main  1965         program.  1966         """  1967   1968         path = self.get_temp_path()  1969   1970         init_item(self.temp_usage, path, list)  1971         self.temp_usage[path].append(name)  1972   1973     def remove_temps(self, names):  1974   1975         """  1976         Remove 'names' from temporary storage allocations, each instance  1977         removing each request for storage.  1978         """  1979   1980         path = self.get_temp_path()  1981   1982         for name in names:  1983             if self.uses_temp(path, name):  1984                 self.temp_usage[path].remove(name)  1985   1986     def uses_temp(self, path, name):  1987   1988         """  1989         Return whether the given namespace 'path' employs a temporary variable  1990         with the given 'name'. Note that 'path' should only be a module or a  1991         function or method, not a class.  1992         """  1993   1994         return self.temp_usage.has_key(path) and name in self.temp_usage[path]  1995   1996     def make_negation(self, expr):  1997   1998         "Return a negated form of 'expr'."  1999   2000         result = NegationResult(expr)  2001   2002         # Negation discards the temporary results of its operand.  2003   2004         temps = expr.discards_temporary()  2005         if temps:  2006             self.remove_temps(temps)  2007   2008         return result  2009   2010     # Output generation.  2011   2012     def start_output(self):  2013   2014         "Write the declarations at the top of each source file."  2015   2016         print >>self.out, """\  2017 #include "types.h"  2018 #include "exceptions.h"  2019 #include "ops.h"  2020 #include "progconsts.h"  2021 #include "progops.h"  2022 #include "progtypes.h"  2023 #include "main.h"  2024 """  2025   2026     def start_unit(self):  2027   2028         "Record output within a generated function for later use."  2029   2030         self.out = StringIO()  2031   2032     def end_unit(self):  2033   2034         "Restore the output stream."  2035   2036         out = self.out  2037         self.out = self.out_toplevel  2038         return out  2039   2040     def flush_unit(self, name, out):  2041   2042         "Add declarations and generated code."  2043   2044         self.write_temporaries(name)  2045         print >>self.out  2046         out.seek(0)  2047         self.out.write(out.read())  2048   2049     def start_module(self):  2050   2051         "Write the start of each module's main function."  2052   2053         print >>self.out, "void __main_%s()" % encode_path(self.name)  2054         print >>self.out, "{"  2055         self.indent += 1  2056   2057         # Define temporary variables, excluded from the module structure itself.  2058   2059         tempnames = []  2060   2061         for n in self.importer.all_module_attrs[self.name]:  2062             if n.startswith("$t"):  2063                 tempnames.append(encode_path(n))  2064   2065         if tempnames:  2066             tempnames.sort()  2067             self.writeline("__attr %s;" % ", ".join(tempnames))  2068   2069         self.start_unit()  2070   2071     def end_module(self):  2072   2073         "End each module by closing its main function."  2074   2075         out = self.end_unit()  2076         self.flush_unit(self.name, out)  2077   2078         self.indent -= 1  2079         print >>self.out, "}"  2080   2081     def start_function(self, name):  2082   2083         "Start the function having the given 'name'."  2084   2085         self.indent += 1  2086   2087         self.start_unit()  2088   2089     def end_function(self, name):  2090   2091         "End the function having the given 'name'."  2092   2093         out = self.end_unit()  2094   2095         # Write the signature at the top indentation level.  2096   2097         self.indent -= 1  2098         self.write_parameters(name)  2099         print >>self.out, "{"  2100   2101         # Obtain local names from parameters.  2102   2103         parameters = self.importer.function_parameters[name]  2104         locals = self.importer.function_locals[name].keys()  2105         names = []  2106         volatile_names = []  2107   2108         for n in locals:  2109   2110             # Filter out special names and parameters. Note that self is a local  2111             # regardless of whether it originally appeared in the parameters or  2112             # not.  2113   2114             if n.startswith("$l") or n in parameters or n == "self":  2115                 continue  2116             if n in self.volatile_locals:  2117                 volatile_names.append(encode_path(n))  2118             else:  2119                 names.append(encode_path(n))  2120   2121         # Emit required local names at the function indentation level.  2122   2123         self.indent += 1  2124   2125         if names:  2126             names.sort()  2127             self.writeline("__attr %s;" % ", ".join(names))  2128   2129         if volatile_names:  2130             volatile_names.sort()  2131             self.writeline("volatile __attr %s;" % ", ".join(volatile_names))  2132   2133         self.flush_unit(name, out)  2134   2135         self.indent -= 1  2136         print >>self.out, "}"  2137         print >>self.out  2138   2139     def write_parameters(self, name):  2140   2141         """  2142         For the function having the given 'name', write definitions of  2143         parameters found in the arguments array.  2144         """  2145   2146         # Generate any self reference.  2147   2148         l = []  2149   2150         if self.is_method(name):  2151             l.append("__attr self")  2152         else:  2153             l.append("__attr __self")  2154   2155         # Generate aliases for the parameters.  2156   2157         for parameter in self.importer.function_parameters[name]:  2158             l.append("%s__attr %s" % (  2159                 parameter in self.volatile_locals and "volatile " or "",  2160                 encode_path(parameter)))  2161   2162         self.writeline("__attr %s(%s)" % (  2163             encode_function_pointer(name), ", ".join(l)))  2164   2165     def write_temporaries(self, name):  2166   2167         "Write temporary storage employed by 'name'."  2168   2169         # Provide space for the recorded number of temporary variables.  2170   2171         if self.uses_temp(name, "__tmp_targets"):  2172             self.writeline("__attr __tmp_targets[%d];" % self.max_function_target)  2173   2174         if self.uses_temp(name, "__tmp_contexts"):  2175             self.writeline("__attr __tmp_contexts[%d];" % self.max_context_index)  2176   2177         if self.uses_temp(name, "__tmp_values"):  2178             self.writeline("__attr __tmp_values[%d];" % self.max_accessor_index)  2179   2180         # Add temporary variable usage details.  2181   2182         if self.uses_temp(name, "__tmp_private_context"):  2183             self.writeline("__attr __tmp_private_context;")  2184         if self.uses_temp(name, "__tmp_target_value"):  2185             self.writeline("__attr __tmp_target_value;")  2186         if self.uses_temp(name, "__tmp_result"):  2187             self.writeline("__attr __tmp_result;")  2188   2189         module = self.importer.get_module(self.name)  2190   2191         if name in module.exception_namespaces:  2192             self.writeline("__exc __tmp_exc;")  2193   2194     def start_if(self, first, test_ref):  2195         statement = "%sif" % (not first and "else " or "")  2196   2197         # Consume logical results directly.  2198   2199         if isinstance(test_ref, LogicalResult):  2200             self.writeline("%s %s" % (statement, test_ref.apply_test()))  2201             temps = test_ref.discards_temporary()  2202             if temps:  2203                 self.remove_temps(temps)  2204         else:  2205             self.writeline("%s (__BOOL(%s))" % (statement, test_ref))  2206   2207         self.writeline("{")  2208         self.indent += 1  2209   2210     def end_if(self):  2211         self.indent -= 1  2212         self.writeline("}")  2213   2214     def start_else(self):  2215         self.writeline("else")  2216         self.writeline("{")  2217         self.indent += 1  2218   2219     def end_else(self):  2220         self.indent -= 1  2221         self.writeline("}")  2222   2223     def statement(self, expr):  2224         s = str(expr)  2225         if s:  2226             self.writestmt("%s;" % s)  2227   2228     def statements(self, results):  2229         for result in results:  2230             self.statement(result)  2231   2232     def writeline(self, s):  2233         print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1))  2234   2235     def writestmt(self, s):  2236         self.writeline(s)  2237   2238     def write_comment(self, s):  2239         self.writestmt("/* %s */" % s)  2240   2241     def pad(self, extra=0):  2242         return (self.indent + extra) * self.tabstop  2243   2244     def indenttext(self, s, levels):  2245         lines = s.split("\n")  2246         out = [lines[0]]  2247         for line in lines[1:]:  2248             out.append(levels * self.tabstop + line)  2249             if line.endswith("("):  2250                 levels += 1  2251             elif line.startswith(")"):  2252                 levels -= 1  2253         return "\n".join(out)  2254   2255 # vim: tabstop=4 expandtab shiftwidth=4