Lichen

translator.py

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