Lichen

translator.py

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