Lichen

translator.py

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