Lichen

translator.py

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