Lichen

translator.py

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