Lichen

translator.py

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