Lichen

translator.py

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