Lichen

translator.py

701:7edcb1489c58
2017-03-11 Paul Boddie Fixed resolution of local and undetermined name references for initialisers.
     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 PredefinedConstantRef("None")   832         if not isinstance(expr, ReturnRef):   833             self.writestmt("return %s;" % expr)   834    835         self.in_conditional = in_conditional   836    837         self.end_function(function_name)   838    839     def generate_guard(self, name):   840    841         """   842         Get the accessor details for 'name', found in the current namespace, and   843         generate any guards defined for it.   844         """   845    846         # Obtain the location, keeping track of assignment versions.   847    848         location = self.get_accessor_location(name)   849         test = self.deducer.accessor_guard_tests.get(location)   850    851         # Generate any guard from the deduced information.   852    853         if test:   854             guard, guard_type = test   855    856             if guard == "specific":   857                 ref = first(self.deducer.accessor_all_types[location])   858                 argstr = "&%s" % encode_path(ref.get_origin())   859             elif guard == "common":   860                 ref = first(self.deducer.accessor_all_general_types[location])   861                 argstr = encode_path(encode_type_attribute(ref.get_origin()))   862             else:   863                 return   864    865             # Produce an appropriate access to an attribute's value.   866    867             parameters = self.importer.function_parameters.get(self.get_namespace_path())   868             if parameters and name in parameters:   869                 name_to_value = "%s->value" % name   870             else:   871                 name_to_value = "%s.value" % name   872    873             # Write a test that raises a TypeError upon failure.   874    875             self.writestmt("if (!__test_%s_%s(%s, %s)) __raise_type_error();" % (   876                 guard, guard_type, name_to_value, argstr))   877    878     def process_function_node(self, n):   879    880         """   881         Process the given function, lambda, if expression or list comprehension   882         node 'n', generating any initialisation statements.   883         """   884    885         # Where a function is declared conditionally, use a separate name for   886         # the definition, and assign the definition to the stated name.   887    888         original_name = n.name   889    890         if self.in_conditional or self.in_function:   891             name = self.get_lambda_name()   892         else:   893             name = n.name   894    895         objpath = self.get_object_path(name)   896    897         # Obtain details of the defaults.   898    899         defaults = self.process_function_defaults(n, name, objpath)   900         if defaults:   901             for default in defaults:   902                 self.writeline("%s;" % default)   903    904         # Where a function is set conditionally or where the name may refer to   905         # different values, assign the name.   906    907         ref = self.importer.identify(objpath)   908    909         if self.in_conditional or self.in_function:   910             self.process_assignment_for_object(original_name, compiler.ast.Name(name))   911         elif not ref.static():   912             context = self.is_method(objpath)   913    914             self.process_assignment_for_object(original_name,   915                 make_expression("__ATTRVALUE(&%s)" % encode_path(objpath)))   916    917     def process_function_defaults(self, n, name, objpath, instance_name=None):   918    919         """   920         Process the given function or lambda node 'n', initialising defaults   921         that are dynamically set. The given 'name' indicates the name of the   922         function. The given 'objpath' indicates the origin of the function.   923         The given 'instance_name' indicates the name of any separate instance   924         of the function created to hold the defaults.   925    926         Return a list of operations setting defaults on a function instance.   927         """   928    929         function_name = self.get_object_path(name)   930         function_defaults = self.importer.function_defaults.get(function_name)   931         if not function_defaults:   932             return None   933    934         # Determine whether any unidentified defaults are involved.   935    936         for argname, default in function_defaults:   937             if not default.static():   938                 break   939         else:   940             return None   941    942         # Handle bound methods.   943    944         if not instance_name:   945             instance_name = "&%s" % encode_path(objpath)   946    947         # Where defaults are involved but cannot be identified, obtain a new   948         # instance of the lambda and populate the defaults.   949    950         defaults = []   951    952         # Join the original defaults with the inspected defaults.   953    954         original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default]   955    956         for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)):   957    958             # Obtain any reference for the default.   959    960             if original:   961                 argname, default = original   962                 name_ref = self.process_structure_node(default)   963             elif inspected:   964                 argname, default = inspected   965                 name_ref = TrResolvedNameRef(argname, default)   966             else:   967                 continue   968    969             # Generate default initialisers except when constants are employed.   970             # Constants should be used when populating the function structures.   971    972             if name_ref and not isinstance(name_ref, TrConstantValueRef):   973                 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref))   974    975         return defaults   976    977     def process_if_node(self, n):   978    979         """   980         Process the given "if" node 'n'.   981         """   982    983         first = True   984         for test, body in n.tests:   985             test_ref = self.process_structure_node(test)   986             self.start_if(first, test_ref)   987    988             in_conditional = self.in_conditional   989             self.in_conditional = True   990             self.process_structure_node(body)   991             self.in_conditional = in_conditional   992    993             self.end_if()   994             first = False   995    996         if n.else_:   997             self.start_else()   998             self.process_structure_node(n.else_)   999             self.end_else()  1000   1001         print >>self.out  1002   1003     def process_invocation_node(self, n):  1004   1005         "Process the given invocation node 'n'."  1006   1007         # Any invocations in the expression will store target details in a  1008         # different location.  1009   1010         self.next_target()  1011   1012         in_argument_list = self.in_argument_list  1013         self.in_argument_list = False  1014   1015         # Process the expression.  1016   1017         expr = self.process_structure_node(n.node)  1018   1019         # Reference the current target again.  1020   1021         self.in_argument_list = in_argument_list  1022         self.function_target -= 1  1023   1024         # Obtain details of the invocation expression.  1025   1026         objpath = expr.get_origin()  1027         location = expr.access_location()  1028         locations = expr.access_locations()  1029   1030         # Identified target details.  1031   1032         target = None  1033         target_structure = None  1034   1035         # Specific function target information.  1036   1037         function = None  1038   1039         # Instantiation involvement.  1040   1041         instantiation = False  1042         literal_instantiation = False  1043   1044         # Invocation requirements.  1045   1046         context_required = True  1047         have_access_context = isinstance(expr, AttrResult)  1048         context_identity = have_access_context and expr.context()  1049         parameters = None  1050   1051         # Obtain details of the callable and of its parameters.  1052   1053         # Literals may be instantiated specially.  1054   1055         if expr.is_name() and expr.name.startswith("$L") and objpath:  1056             instantiation = literal_instantiation = objpath  1057             target = encode_literal_instantiator(objpath)  1058             context_required = False  1059   1060         # Identified targets employ function pointers directly.  1061   1062         elif objpath:  1063             parameters = self.importer.function_parameters.get(objpath)  1064   1065             # Class invocation involves instantiators.  1066   1067             if expr.has_kind("<class>"):  1068                 instantiation = objpath  1069                 target = encode_instantiator_pointer(objpath)  1070                 init_ref = self.importer.all_class_attrs[objpath]["__init__"]  1071                 target_structure = "&%s" % encode_path(init_ref)  1072                 context_required = False  1073   1074             # Only plain functions and bound methods employ function pointers.  1075   1076             elif expr.has_kind("<function>"):  1077                 function = objpath  1078   1079                 # Test for functions and methods.  1080   1081                 context_required = self.is_method(objpath)  1082   1083                 accessor_kinds = location and self.get_accessor_kinds([location]) or \  1084                                  locations and self.get_accessor_kinds(locations)  1085   1086                 instance_accessor = accessor_kinds and \  1087                                     len(accessor_kinds) == 1 and \  1088                                     first(accessor_kinds) == "<instance>"  1089   1090                 # Only identify certain bound methods or functions.  1091   1092                 if not context_required or instance_accessor:  1093                     target = encode_function_pointer(objpath)  1094   1095                 # Access bound method defaults even if it is not clear whether  1096                 # the accessor is appropriate.  1097   1098                 target_structure = "&%s" % encode_path(objpath)  1099   1100         # Other targets are retrieved at run-time. Some information about them  1101         # may be available and be used to provide warnings about argument  1102         # compatibility.  1103   1104         elif self.importer.give_warning("args"):  1105             unsuitable = self.get_referenced_attribute_invocations(location)  1106   1107             if unsuitable:  1108                 for ref in unsuitable:  1109                     _objpath = ref.get_origin()  1110                     num_parameters = len(self.importer.function_parameters[_objpath])  1111                     print >>sys.stderr, \  1112                         "In %s, at line %d, inappropriate number of " \  1113                         "arguments given. Need %d arguments to call %s." % (  1114                         self.get_namespace_path(), n.lineno, num_parameters,  1115                         _objpath)  1116   1117         # Determine any readily-accessible target identity.  1118   1119         target_named = expr.is_name() and str(expr) or None  1120         target_stored = "__tmp_targets[%d]" % self.function_target  1121   1122         target_identity = target or target_named  1123         target_var = target_identity or target_stored  1124         context_var = target_named or target_stored  1125   1126         if not target_identity:  1127             self.record_temp("__tmp_targets")  1128   1129         if context_identity and context_identity.startswith("__tmp_contexts"):  1130             self.record_temp("__tmp_contexts")  1131   1132         # Arguments are presented in a temporary frame array with any context  1133         # always being the first argument. Where it would be unused, it may be  1134         # set to null.  1135   1136         if context_required:  1137             if have_access_context:  1138                 args = ["__ATTRVALUE(%s)" % context_identity]  1139             else:  1140                 args = ["__CONTEXT_AS_VALUE(%s)" % context_var]  1141         else:  1142             args = ["__NULL"]  1143   1144         # Complete the array with null values, permitting tests for a complete  1145         # set of arguments.  1146   1147         args += [None] * (parameters is None and len(n.args) or parameters is not None and len(parameters) or 0)  1148         kwcodes = []  1149         kwargs = []  1150   1151         # Any invocations in the arguments will store target details in a  1152         # different location.  1153   1154         function_target = self.function_target  1155   1156         if not target_identity:  1157             self.next_target()  1158   1159         in_argument_list = self.in_argument_list  1160         self.in_argument_list = True  1161   1162         for i, arg in enumerate(n.args):  1163             argexpr = self.process_structure_node(arg)  1164   1165             # Store a keyword argument, either in the argument list or  1166             # in a separate keyword argument list for subsequent lookup.  1167   1168             if isinstance(arg, compiler.ast.Keyword):  1169   1170                 # With knowledge of the target, store the keyword  1171                 # argument directly.  1172   1173                 if parameters:  1174                     try:  1175                         argnum = parameters.index(arg.name)  1176                     except ValueError:  1177                         raise TranslateError("Argument %s is not recognised." % arg.name,  1178                                              self.get_namespace_path(), n)  1179                     args[argnum+1] = str(argexpr)  1180   1181                 # Otherwise, store the details in a separate collection.  1182   1183                 else:  1184                     kwargs.append(str(argexpr))  1185                     kwcodes.append("{%s, %s}" % (  1186                         encode_ppos(arg.name), encode_pcode(arg.name)))  1187   1188             # Store non-keyword arguments in the argument list, rejecting  1189             # superfluous arguments.  1190   1191             else:  1192                 try:  1193                     args[i+1] = str(argexpr)  1194                 except IndexError:  1195                     raise TranslateError("Too many arguments specified.",  1196                                          self.get_namespace_path(), n)  1197   1198         # Reference the current target again.  1199   1200         self.in_argument_list = in_argument_list  1201   1202         if not self.in_argument_list:  1203             self.function_target = function_target  1204   1205         # Defaults are added to the frame where arguments are missing.  1206   1207         if parameters:  1208             function_defaults = self.importer.function_defaults.get(objpath)  1209             if function_defaults:  1210   1211                 # Visit each default and set any missing arguments.  1212                 # Use the target structure to obtain defaults, as opposed to the  1213                 # actual function involved.  1214   1215                 for i, (argname, default) in enumerate(function_defaults):  1216                     argnum = parameters.index(argname)  1217                     if not args[argnum+1]:  1218                         args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i)  1219   1220         # Test for missing arguments.  1221   1222         if None in args:  1223             raise TranslateError("Not all arguments supplied.",  1224                                  self.get_namespace_path(), n)  1225   1226         # Encode the arguments.  1227   1228         argstr = "__ARGS(%s)" % ", ".join(args)  1229         kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0"  1230         kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0"  1231   1232         # Where literal instantiation is occurring, add an argument indicating  1233         # the number of values.  1234   1235         if literal_instantiation:  1236             argstr += ", %d" % (len(args) - 1)  1237   1238         # First, the invocation expression is presented.  1239   1240         stages = []  1241   1242         # Without a known specific callable, the expression provides the target.  1243   1244         if not target or context_required:  1245   1246             # The context is set in the expression.  1247   1248             if target and not target_named:  1249   1250                 # Test whether the expression provides anything.  1251   1252                 if expr:  1253                     stages.append(str(expr))  1254   1255             elif not target_identity:  1256                 stages.append("%s = %s" % (target_var, expr))  1257   1258         # Any specific callable is then obtained for invocation.  1259   1260         if target:  1261             stages.append(target)  1262   1263         # Methods accessed via unidentified accessors are obtained for  1264         # invocation.  1265   1266         elif function:  1267             if context_required:  1268                 if have_access_context:  1269                     stages.append("__get_function(%s, %s)" % (  1270                         context_identity, target_var))  1271                 else:  1272                     stages.append("__get_function(__CONTEXT_AS_VALUE(%s).value, %s)" % (  1273                         context_var, target_var))  1274             else:  1275                 stages.append("__load_via_object(%s.value, __fn__).fn" % target_var)  1276   1277         # With a known target, the function is obtained directly and called.  1278         # By putting the invocation at the end of the final element in the  1279         # instruction sequence (the stages), the result becomes the result of  1280         # the sequence. Moreover, the parameters become part of the sequence  1281         # and thereby participate in a guaranteed evaluation order.  1282   1283         if target or function:  1284             stages[-1] += "(%s)" % argstr  1285             if instantiation:  1286                 return InstantiationResult(instantiation, stages)  1287             else:  1288                 return InvocationResult(stages)  1289   1290         # With unknown targets, the generic invocation function is applied to  1291         # the callable and argument collections.  1292   1293         else:  1294             stages.append("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % (  1295                 target_var,  1296                 self.always_callable and 1 or 0,  1297                 len(kwargs), kwcodestr, kwargstr,  1298                 len(args), argstr))  1299             return InvocationResult(stages)  1300   1301     def next_target(self):  1302   1303         "Allocate the next function target storage."  1304   1305         self.function_target += 1  1306         self.max_function_targets = max(self.function_target, self.max_function_targets)  1307   1308     def always_callable(self, refs):  1309   1310         "Determine whether all 'refs' are callable."  1311   1312         for ref in refs:  1313             if not ref.static():  1314                 return False  1315             else:  1316                 origin = ref.final()  1317                 if not self.importer.get_attribute(origin, "__fn__"):  1318                     return False  1319         return True  1320   1321     def need_default_arguments(self, objpath, nargs):  1322   1323         """  1324         Return whether any default arguments are needed when invoking the object  1325         given by 'objpath'.  1326         """  1327   1328         parameters = self.importer.function_parameters.get(objpath)  1329         return nargs < len(parameters)  1330   1331     def process_lambda_node(self, n):  1332   1333         "Process the given lambda node 'n'."  1334   1335         name = self.get_lambda_name()  1336         function_name = self.get_object_path(name)  1337   1338         defaults = self.process_function_defaults(n, name, function_name, "__tmp_value")  1339   1340         # Without defaults, produce an attribute referring to the function.  1341   1342         if not defaults:  1343             return make_expression("__ATTRVALUE(&%s)" % encode_path(function_name))  1344   1345         # With defaults, copy the function structure and set the defaults on the  1346         # copy.  1347   1348         else:  1349             self.record_temp("__tmp_value")  1350             return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, __ATTRVALUE(__tmp_value))" % (  1351                 encode_path(function_name),  1352                 encode_symbol("obj", function_name),  1353                 ", ".join(defaults)))  1354   1355     def process_logical_node(self, n):  1356   1357         "Process the given operator node 'n'."  1358   1359         self.record_temp("__tmp_result")  1360   1361         conjunction = isinstance(n, compiler.ast.And)  1362         results = []  1363   1364         for node in n.nodes:  1365             results.append(self.process_structure_node(node))  1366   1367         return LogicalOperationResult(results, conjunction)  1368   1369     def process_name_node(self, n, expr=None):  1370   1371         "Process the given name node 'n' with the optional assignment 'expr'."  1372   1373         # Determine whether the name refers to a static external entity.  1374   1375         if n.name in predefined_constants:  1376             return PredefinedConstantRef(n.name, expr)  1377   1378         # Convert literal references, operator function names, and print  1379         # function names to references.  1380   1381         elif n.name.startswith("$L") or n.name.startswith("$op") or \  1382              n.name.startswith("$print"):  1383   1384             ref, paths = self.importer.get_module(self.name).special[n.name]  1385             return TrResolvedNameRef(n.name, ref)  1386   1387         # Temporary names are output program locals.  1388   1389         elif n.name.startswith("$t"):  1390             return TrResolvedNameRef(n.name, Reference("<var>"), expr=expr)  1391   1392         # Get the appropriate name for the name reference, using the same method  1393         # as in the inspector.  1394   1395         path = self.get_namespace_path()  1396         objpath = self.get_object_path(n.name)  1397   1398         # Determine any assigned globals.  1399   1400         globals = self.importer.get_module(self.name).scope_globals.get(path)  1401   1402         # Explicitly declared globals.  1403   1404         if globals and n.name in globals:  1405             objpath = self.get_global_path(n.name)  1406             is_global = True  1407   1408         # Implicitly referenced globals in functions.  1409   1410         elif self.in_function:  1411             is_global = n.name not in self.importer.function_locals[path]  1412   1413         # Implicitly referenced globals elsewhere.  1414   1415         else:  1416             namespace = self.importer.identify(path)  1417             is_global = not self.importer.get_attributes(namespace, n.name)  1418   1419         # Get the static identity of the name.  1420   1421         ref = self.importer.identify(objpath)  1422         if ref and not ref.get_name():  1423             ref = ref.alias(objpath)  1424   1425         # Obtain any resolved names for non-assignment names.  1426   1427         if not expr and not ref and self.in_function:  1428             locals = self.importer.function_locals.get(path)  1429             ref = locals and locals.get(n.name)  1430   1431         # Determine whether the name refers to a parameter. The generation of  1432         # parameter references is different from other names.  1433   1434         parameters = self.importer.function_parameters.get(path)  1435         parameter = n.name == "self" and self.in_method() or \  1436                     parameters and n.name in parameters  1437   1438         # Find any invocation or alias details.  1439   1440         name = self.get_name_for_tracking(n.name, is_global=is_global)  1441         location = not expr and self.get_access_location(name)  1442   1443         # Mark any local assignments as volatile in exception blocks.  1444   1445         if expr and self.in_function and not is_global and self.in_try_except:  1446             self.make_volatile(n.name)  1447   1448         # Qualified names are used for resolved static references or for  1449         # static namespace members. The reference should be configured to return  1450         # such names.  1451   1452         name_ref = TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global,  1453                                      parameter=parameter, location=location)  1454         result = self.get_aliases(name_ref)  1455         return result or name_ref  1456   1457     def get_aliases(self, name_ref):  1458   1459         "Return alias references for the given 'name_ref'."  1460   1461         location = name_ref.access_location()  1462   1463         accessor_locations = location and self.deducer.get_accessors_for_access(location)  1464         alias_refs = set()  1465         access_locations = set()  1466   1467         if accessor_locations:  1468             for accessor_location in accessor_locations:  1469                 aliased_accesses = self.deducer.alias_index.get(accessor_location)  1470                 if not aliased_accesses:  1471                     continue  1472                 access_locations.update(aliased_accesses)  1473                 refs = self.deducer.referenced_objects.get(accessor_location)  1474                 if refs:  1475                     alias_refs.update(refs)  1476   1477         return AliasResult(name_ref, alias_refs, access_locations)  1478   1479     def make_volatile(self, name):  1480   1481         "Record 'name' as volatile in the current namespace."  1482   1483         self.volatile_locals.add(name)  1484   1485     def process_not_node(self, n):  1486   1487         "Process the given operator node 'n'."  1488   1489         return self.make_negation(self.process_structure_node(n.expr))  1490   1491     def process_raise_node(self, n):  1492   1493         "Process the given raise node 'n'."  1494   1495         # NOTE: Determine which raise statement variants should be permitted.  1496   1497         if n.expr1:  1498   1499             # Names with accompanying arguments are treated like invocations.  1500   1501             if n.expr2:  1502                 call = compiler.ast.CallFunc(n.expr1, [n.expr2])  1503                 exc = self.process_structure_node(call)  1504                 self.writestmt("__Raise(%s);" % exc)  1505   1506             # Raise instances, testing the kind at run-time if necessary and  1507             # instantiating any non-instance.  1508   1509             else:  1510                 exc = self.process_structure_node(n.expr1)  1511   1512                 if isinstance(exc, TrInstanceRef):  1513                     self.writestmt("__Raise(%s);" % exc)  1514                 else:  1515                     self.writestmt("__Raise(__ensure_instance(%s));" % exc)  1516         else:  1517             self.writestmt("__Throw(__tmp_exc);")  1518   1519     def process_return_node(self, n):  1520   1521         "Process the given return node 'n'."  1522   1523         expr = self.process_structure_node(n.value) or PredefinedConstantRef("None")  1524         if self.in_try_finally or self.in_try_except:  1525             self.writestmt("__Return(%s);" % expr)  1526         else:  1527             self.writestmt("return %s;" % expr)  1528   1529         return ReturnRef()  1530   1531     def process_try_node(self, n):  1532   1533         """  1534         Process the given "try...except" node 'n'.  1535         """  1536   1537         in_try_except = self.in_try_except  1538         self.in_try_except = True  1539   1540         # Use macros to implement exception handling.  1541   1542         self.writestmt("__Try")  1543         self.writeline("{")  1544         self.indent += 1  1545         self.process_structure_node(n.body)  1546   1547         # Put the else statement in another try block that handles any raised  1548         # exceptions and converts them to exceptions that will not be handled by  1549         # the main handling block.  1550   1551         if n.else_:  1552             self.writestmt("__Try")  1553             self.writeline("{")  1554             self.indent += 1  1555             self.process_structure_node(n.else_)  1556             self.indent -= 1  1557             self.writeline("}")  1558             self.writeline("__Catch (__tmp_exc)")  1559             self.writeline("{")  1560             self.indent += 1  1561             self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);")  1562             self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);")  1563             self.indent -= 1  1564             self.writeline("}")  1565   1566         # Complete the try block and enter the finally block, if appropriate.  1567   1568         if self.in_try_finally:  1569             self.writestmt("__Complete;")  1570   1571         self.indent -= 1  1572         self.writeline("}")  1573   1574         self.in_try_except = in_try_except  1575   1576         # Handlers are tests within a common handler block.  1577   1578         self.writeline("__Catch (__tmp_exc)")  1579         self.writeline("{")  1580         self.indent += 1  1581   1582         # Introduce an if statement to handle the completion of a try block.  1583   1584         self.process_try_completion()  1585   1586         # Handle exceptions in else blocks converted to __RaiseElse, converting  1587         # them back to normal exceptions.  1588   1589         if n.else_:  1590             self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);")  1591   1592         # Exception handling.  1593   1594         for name, var, handler in n.handlers:  1595   1596             # Test for specific exceptions.  1597   1598             if name is not None:  1599                 name_ref = self.process_structure_node(name)  1600                 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref)  1601             else:  1602                 self.writeline("else if (1)")  1603   1604             self.writeline("{")  1605             self.indent += 1  1606   1607             # Establish the local for the handler.  1608   1609             if var is not None:  1610                 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg")))  1611   1612             if handler is not None:  1613                 self.process_structure_node(handler)  1614   1615             self.indent -= 1  1616             self.writeline("}")  1617   1618         # Re-raise unhandled exceptions.  1619   1620         self.writeline("else __Throw(__tmp_exc);")  1621   1622         # End the handler block.  1623   1624         self.indent -= 1  1625         self.writeline("}")  1626         print >>self.out  1627   1628     def process_try_finally_node(self, n):  1629   1630         """  1631         Process the given "try...finally" node 'n'.  1632         """  1633   1634         in_try_finally = self.in_try_finally  1635         self.in_try_finally = True  1636   1637         # Use macros to implement exception handling.  1638   1639         self.writestmt("__Try")  1640         self.writeline("{")  1641         self.indent += 1  1642         self.process_structure_node(n.body)  1643         self.indent -= 1  1644         self.writeline("}")  1645   1646         self.in_try_finally = in_try_finally  1647   1648         # Finally clauses handle special exceptions.  1649   1650         self.writeline("__Catch (__tmp_exc)")  1651         self.writeline("{")  1652         self.indent += 1  1653         self.process_structure_node(n.final)  1654   1655         # Introduce an if statement to handle the completion of a try block.  1656   1657         self.process_try_completion()  1658         self.writeline("else __Throw(__tmp_exc);")  1659   1660         self.indent -= 1  1661         self.writeline("}")  1662         print >>self.out  1663   1664     def process_try_completion(self):  1665   1666         "Generate a test for the completion of a try block."  1667   1668         self.writestmt("if (__tmp_exc.completing)")  1669         self.writeline("{")  1670         self.indent += 1  1671   1672         # Do not return anything at the module level.  1673   1674         if self.get_namespace_path() != self.name:  1675   1676             # Only use the normal return statement if no surrounding try blocks  1677             # apply.  1678   1679             if not self.in_try_finally and not self.in_try_except:  1680                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;")  1681             else:  1682                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);")  1683   1684         self.indent -= 1  1685         self.writeline("}")  1686   1687     def process_while_node(self, n):  1688   1689         "Process the given while node 'n'."  1690   1691         self.writeline("while (1)")  1692         self.writeline("{")  1693         self.indent += 1  1694         test = self.process_structure_node(n.test)  1695   1696         # Emit the loop termination condition unless "while <true value>" is  1697         # indicated.  1698   1699         if not (isinstance(test, PredefinedConstantRef) and test.value):  1700   1701             # Emit a negated test of the continuation condition.  1702   1703             self.start_if(True, self.make_negation(test))  1704             if n.else_:  1705                 self.process_structure_node(n.else_)  1706             self.writestmt("break;")  1707             self.end_if()  1708   1709         in_conditional = self.in_conditional  1710         self.in_conditional = True  1711         self.process_structure_node(n.body)  1712         self.in_conditional = in_conditional  1713   1714         self.indent -= 1  1715         self.writeline("}")  1716         print >>self.out  1717   1718     # Special variable usage.  1719   1720     def get_temp_path(self):  1721   1722         """  1723         Return the appropriate namespace path for temporary names in the current  1724         namespace.  1725         """  1726   1727         if self.in_function:  1728             return self.get_namespace_path()  1729         else:  1730             return self.name  1731   1732     def record_temp(self, name):  1733   1734         """  1735         Record the use of the temporary 'name' in the current namespace. At the  1736         class or module level, the temporary name is associated with the module,  1737         since the variable will then be allocated in the module's own main  1738         program.  1739         """  1740   1741         path = self.get_temp_path()  1742   1743         init_item(self.temp_usage, path, list)  1744         self.temp_usage[path].append(name)  1745   1746     def remove_temps(self, names):  1747   1748         """  1749         Remove 'names' from temporary storage allocations, each instance  1750         removing each request for storage.  1751         """  1752   1753         path = self.get_temp_path()  1754   1755         for name in names:  1756             if self.uses_temp(path, name):  1757                 self.temp_usage[path].remove(name)  1758   1759     def uses_temp(self, path, name):  1760   1761         """  1762         Return whether the given namespace 'path' employs a temporary variable  1763         with the given 'name'. Note that 'path' should only be a module or a  1764         function or method, not a class.  1765         """  1766   1767         return self.temp_usage.has_key(path) and name in self.temp_usage[path]  1768   1769     def make_negation(self, expr):  1770   1771         "Return a negated form of 'expr'."  1772   1773         result = NegationResult(expr)  1774   1775         # Negation discards the temporary results of its operand.  1776   1777         temps = expr.discards_temporary()  1778         if temps:  1779             self.remove_temps(temps)  1780   1781         return result  1782   1783     # Output generation.  1784   1785     def start_output(self):  1786   1787         "Write the declarations at the top of each source file."  1788   1789         print >>self.out, """\  1790 #include "types.h"  1791 #include "exceptions.h"  1792 #include "ops.h"  1793 #include "progconsts.h"  1794 #include "progops.h"  1795 #include "progtypes.h"  1796 #include "main.h"  1797 """  1798   1799     def start_unit(self):  1800   1801         "Record output within a generated function for later use."  1802   1803         self.out = StringIO()  1804   1805     def end_unit(self):  1806   1807         "Restore the output stream."  1808   1809         out = self.out  1810         self.out = self.out_toplevel  1811         return out  1812   1813     def flush_unit(self, name, out):  1814   1815         "Add declarations and generated code."  1816   1817         self.write_temporaries(name)  1818         print >>self.out  1819         out.seek(0)  1820         self.out.write(out.read())  1821   1822     def start_module(self):  1823   1824         "Write the start of each module's main function."  1825   1826         print >>self.out, "void __main_%s()" % encode_path(self.name)  1827         print >>self.out, "{"  1828         self.indent += 1  1829   1830         # Define temporary variables, excluded from the module structure itself.  1831   1832         tempnames = []  1833   1834         for n in self.importer.all_module_attrs[self.name]:  1835             if n.startswith("$t"):  1836                 tempnames.append(encode_path(n))  1837   1838         if tempnames:  1839             tempnames.sort()  1840             self.writeline("__attr %s;" % ", ".join(tempnames))  1841   1842         self.start_unit()  1843   1844     def end_module(self):  1845   1846         "End each module by closing its main function."  1847   1848         out = self.end_unit()  1849         self.flush_unit(self.name, out)  1850   1851         self.indent -= 1  1852         print >>self.out, "}"  1853   1854     def start_function(self, name):  1855   1856         "Start the function having the given 'name'."  1857   1858         print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name)  1859         print >>self.out, "{"  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         # Obtain local names from parameters.  1871   1872         parameters = self.importer.function_parameters[name]  1873         locals = self.importer.function_locals[name].keys()  1874         names = []  1875         volatile_names = []  1876   1877         for n in locals:  1878   1879             # Filter out special names and parameters. Note that self is a local  1880             # regardless of whether it originally appeared in the parameters or  1881             # not.  1882   1883             if n.startswith("$l") or n in parameters or n == "self":  1884                 continue  1885             if n in self.volatile_locals:  1886                 volatile_names.append(encode_path(n))  1887             else:  1888                 names.append(encode_path(n))  1889   1890         # Emit required local names.  1891   1892         if names:  1893             names.sort()  1894             self.writeline("__attr %s;" % ", ".join(names))  1895   1896         if volatile_names:  1897             volatile_names.sort()  1898             self.writeline("volatile __attr %s;" % ", ".join(volatile_names))  1899   1900         self.write_parameters(name)  1901   1902         self.flush_unit(name, out)  1903   1904         self.indent -= 1  1905         print >>self.out, "}"  1906         print >>self.out  1907   1908     def write_temporaries(self, name):  1909   1910         "Write temporary storage employed by 'name'."  1911   1912         # Provide space for the given number of targets.  1913   1914         targets = self.max_function_targets  1915   1916         if self.uses_temp(name, "__tmp_targets"):  1917             self.writeline("__attr __tmp_targets[%d];" % targets)  1918         if self.uses_temp(name, "__tmp_contexts"):  1919             self.writeline("__ref __tmp_contexts[%d];" % targets)  1920   1921         # Add temporary variable usage details.  1922   1923         if self.uses_temp(name, "__tmp_private_context"):  1924             self.writeline("__ref __tmp_private_context;")  1925         if self.uses_temp(name, "__tmp_value"):  1926             self.writeline("__ref __tmp_value;")  1927         if self.uses_temp(name, "__tmp_target_value"):  1928             self.writeline("__ref __tmp_target_value;")  1929         if self.uses_temp(name, "__tmp_result"):  1930             self.writeline("__attr __tmp_result;")  1931   1932         module = self.importer.get_module(self.name)  1933   1934         if name in module.exception_namespaces:  1935             self.writeline("__exc __tmp_exc;")  1936   1937     def write_parameters(self, name):  1938   1939         """  1940         For the function having the given 'name', write definitions of  1941         parameters found in the arguments array.  1942         """  1943   1944         parameters = self.importer.function_parameters[name]  1945   1946         # Generate any self reference.  1947   1948         if self.is_method(name):  1949             self.writeline("__attr * const self = &__args[0];")  1950   1951         # Generate aliases for the parameters.  1952   1953         for i, parameter in enumerate(parameters):  1954             self.writeline("%s__attr * const %s = &__args[%d];" % (  1955                 parameter in self.volatile_locals and "volatile " or "",  1956                 encode_path(parameter), i+1))  1957   1958     def start_if(self, first, test_ref):  1959         statement = "%sif" % (not first and "else " or "")  1960   1961         # Consume logical results directly.  1962   1963         if isinstance(test_ref, LogicalResult):  1964             self.writeline("%s %s" % (statement, test_ref.apply_test()))  1965             temps = test_ref.discards_temporary()  1966             if temps:  1967                 self.remove_temps(temps)  1968         else:  1969             self.writeline("%s (__BOOL(%s))" % (statement, test_ref))  1970   1971         self.writeline("{")  1972         self.indent += 1  1973   1974     def end_if(self):  1975         self.indent -= 1  1976         self.writeline("}")  1977   1978     def start_else(self):  1979         self.writeline("else")  1980         self.writeline("{")  1981         self.indent += 1  1982   1983     def end_else(self):  1984         self.indent -= 1  1985         self.writeline("}")  1986   1987     def statement(self, expr):  1988         s = str(expr)  1989         if s:  1990             self.writestmt("%s;" % s)  1991   1992     def statements(self, results):  1993         for result in results:  1994             self.statement(result)  1995   1996     def writeline(self, s):  1997         print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1))  1998   1999     def writestmt(self, s):  2000         self.writeline(s)  2001   2002     def write_comment(self, s):  2003         self.writestmt("/* %s */" % s)  2004   2005     def pad(self, extra=0):  2006         return (self.indent + extra) * self.tabstop  2007   2008     def indenttext(self, s, levels):  2009         lines = s.split("\n")  2010         out = [lines[0]]  2011         for line in lines[1:]:  2012             out.append(levels * self.tabstop + line)  2013             if line.endswith("("):  2014                 levels += 1  2015             elif line.startswith(")"):  2016                 levels -= 1  2017         return "\n".join(out)  2018   2019 # vim: tabstop=4 expandtab shiftwidth=4