Lichen

translator.py

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