Lichen

translator.py

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