Lichen

translator.py

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