Lichen

translator.py

641:c71722209a3d
2017-03-01 Paul Boddie Added support for preserving attribute and parameter locations, avoiding misidentification issues in existing, preserved object code.
     1 #!/usr/bin/env python     2      3 """     4 Translate programs.     5      6 Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from common import CommonModule, CommonOutput, \    23                    first, get_builtin_class, init_item, is_newer, \    24                    predefined_constants    25 from encoders import encode_access_instruction, encode_access_instruction_arg, \    26                      encode_function_pointer, encode_literal_instantiator, \    27                      encode_instantiator_pointer, encode_path, encode_symbol, \    28                      encode_type_attribute, is_type_attribute    29 from errors import InspectError, TranslateError    30 from os.path import exists, join    31 from os import makedirs    32 from referencing import Reference    33 from results import Result    34 from transresults import TrConstantValueRef, TrInstanceRef, \    35                          TrLiteralSequenceRef, TrResolvedNameRef, \    36                          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         # Attribute access and accessor counting.   124    125         self.attr_accesses = {}   126         self.attr_accessors = {}   127    128         # Special variable usage.   129    130         self.temp_usage = {}   131    132         # Initialise some data used for attribute access generation.   133    134         self.init_substitutions()   135    136     def __repr__(self):   137         return "TranslatedModule(%r, %r)" % (self.name, self.importer)   138    139     def translate(self, filename, output_filename):   140    141         """   142         Parse the file having the given 'filename', writing the translation to   143         the given 'output_filename'.   144         """   145    146         self.parse_file(filename)   147    148         # Collect function namespaces for separate processing.   149    150         self.record_namespaces(self.astnode)   151    152         # Reset the lambda naming (in order to obtain the same names again) and   153         # translate the program.   154    155         self.reset_lambdas()   156    157         self.out_toplevel = self.out = open(output_filename, "w")   158         try:   159             self.start_output()   160    161             # Process namespaces, writing the translation.   162    163             for path, node in self.namespaces:   164                 self.process_namespace(path, node)   165    166             # Process the module namespace including class namespaces.   167    168             self.process_namespace([], self.astnode)   169    170         finally:   171             self.out.close()   172    173     def have_object(self):   174    175         "Return whether a namespace is a recorded object."   176    177         return self.importer.objects.get(self.get_namespace_path())   178    179     def get_builtin_class(self, name):   180    181         "Return a reference to the actual object providing 'name'."   182    183         return self.importer.get_object(get_builtin_class(name))   184    185     def is_method(self, path):   186    187         "Return whether 'path' is a method."   188    189         class_name, method_name = path.rsplit(".", 1)   190         return self.importer.classes.has_key(class_name) and class_name or None   191    192     def in_method(self):   193    194         "Return whether the current namespace provides a method."   195    196         return self.in_function and self.is_method(self.get_namespace_path())   197    198     # Namespace recording.   199    200     def record_namespaces(self, node):   201    202         "Process the program structure 'node', recording namespaces."   203    204         for n in node.getChildNodes():   205             self.record_namespaces_in_node(n)   206    207     def record_namespaces_in_node(self, node):   208    209         "Process the program structure 'node', recording namespaces."   210    211         # Function namespaces within modules, classes and other functions.   212         # Functions appearing within conditional statements are given arbitrary   213         # names.   214    215         if isinstance(node, compiler.ast.Function):   216             self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name)   217    218         elif isinstance(node, compiler.ast.Lambda):   219             self.record_function_node(node, self.get_lambda_name())   220    221         # Classes are visited, but may be ignored if inside functions.   222    223         elif isinstance(node, compiler.ast.Class):   224             self.enter_namespace(node.name)   225             if self.have_object():   226                 self.record_namespaces(node)   227             self.exit_namespace()   228    229         # Conditional nodes are tracked so that function definitions may be   230         # handled. Since "for" loops are converted to "while" loops, they are   231         # included here.   232    233         elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)):   234             in_conditional = self.in_conditional   235             self.in_conditional = True   236             self.record_namespaces(node)   237             self.in_conditional = in_conditional   238    239         # All other nodes are processed depth-first.   240    241         else:   242             self.record_namespaces(node)   243    244     def record_function_node(self, n, name):   245    246         """   247         Record the given function, lambda, if expression or list comprehension   248         node 'n' with the given 'name'.   249         """   250    251         self.in_function = True   252         self.enter_namespace(name)   253    254         if self.have_object():   255    256             # Record the namespace path and the node itself.   257    258             self.namespaces.append((self.namespace_path[:], n))   259             self.record_namespaces_in_node(n.code)   260    261         self.exit_namespace()   262         self.in_function = False   263    264     # Constant referencing.   265    266     def get_literal_instance(self, n, name=None):   267    268         """   269         For node 'n', return a reference for the type of the given 'name', or if   270         'name' is not specified, deduce the type from the value.   271         """   272    273         # Handle stray None constants (Sliceobj seems to produce them).   274    275         if name is None and n.value is None:   276             return self.process_name_node(compiler.ast.Name("None"))   277    278         if name in ("dict", "list", "tuple"):   279             ref = self.get_builtin_class(name)   280             return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef)   281         else:   282             value, typename, encoding = self.get_constant_value(n.value, n.literals)   283             ref = self.get_builtin_class(typename)   284             value_type = ref.get_origin()   285    286             path = self.get_namespace_path()   287    288             # Obtain the local numbering of the constant and thus the   289             # locally-qualified name.   290    291             local_number = self.importer.all_constants[path][(value, value_type, encoding)]   292             constant_name = "$c%d" % local_number   293             objpath = self.get_object_path(constant_name)   294    295             # Obtain the unique identifier for the constant.   296    297             number = self.optimiser.constant_numbers[objpath]   298             return TrConstantValueRef(constant_name, ref.instance_of(), value, number)   299    300     # Namespace translation.   301    302     def process_namespace(self, path, node):   303    304         """   305         Process the namespace for the given 'path' defined by the given 'node'.   306         """   307    308         self.namespace_path = path   309    310         if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)):   311             self.in_function = True   312             self.process_function_body_node(node)   313         else:   314             self.in_function = False   315             self.function_target = 0   316             self.start_module()   317             self.process_structure(node)   318             self.end_module()   319    320     def process_structure(self, node):   321    322         "Process the given 'node' or result."   323    324         # Handle processing requests on results.   325    326         if isinstance(node, Result):   327             return node   328    329         # Handle processing requests on nodes.   330    331         else:   332             l = CommonModule.process_structure(self, node)   333    334             # Return indications of return statement usage.   335    336             if l and isinstance(l[-1], ReturnRef):   337                 return l[-1]   338             else:   339                 return None   340    341     def process_structure_node(self, n):   342    343         "Process the individual node 'n'."   344    345         # Plain statements emit their expressions.   346    347         if isinstance(n, compiler.ast.Discard):   348             expr = self.process_structure_node(n.expr)   349             self.statement(expr)   350    351         # Module import declarations.   352    353         elif isinstance(n, compiler.ast.From):   354             self.process_from_node(n)   355    356         # Nodes using operator module functions.   357    358         elif isinstance(n, compiler.ast.Operator):   359             return self.process_operator_node(n)   360    361         elif isinstance(n, compiler.ast.AugAssign):   362             self.process_augassign_node(n)   363    364         elif isinstance(n, compiler.ast.Compare):   365             return self.process_compare_node(n)   366    367         elif isinstance(n, compiler.ast.Slice):   368             return self.process_slice_node(n)   369    370         elif isinstance(n, compiler.ast.Sliceobj):   371             return self.process_sliceobj_node(n)   372    373         elif isinstance(n, compiler.ast.Subscript):   374             return self.process_subscript_node(n)   375    376         # Classes are visited, but may be ignored if inside functions.   377    378         elif isinstance(n, compiler.ast.Class):   379             self.process_class_node(n)   380    381         # Functions within namespaces have any dynamic defaults initialised.   382    383         elif isinstance(n, compiler.ast.Function):   384             self.process_function_node(n)   385    386         # Lambdas are replaced with references to separately-generated   387         # functions.   388    389         elif isinstance(n, compiler.ast.Lambda):   390             return self.process_lambda_node(n)   391    392         # Assignments.   393    394         elif isinstance(n, compiler.ast.Assign):   395    396             # Handle each assignment node.   397    398             for node in n.nodes:   399                 self.process_assignment_node(node, n.expr)   400    401         # Accesses.   402    403         elif isinstance(n, compiler.ast.Getattr):   404             return self.process_attribute_access(n)   405    406         # Names.   407    408         elif isinstance(n, compiler.ast.Name):   409             return self.process_name_node(n)   410    411         # Loops and conditionals.   412    413         elif isinstance(n, compiler.ast.For):   414             self.process_for_node(n)   415    416         elif isinstance(n, compiler.ast.While):   417             self.process_while_node(n)   418    419         elif isinstance(n, compiler.ast.If):   420             self.process_if_node(n)   421    422         elif isinstance(n, (compiler.ast.And, compiler.ast.Or)):   423             return self.process_logical_node(n)   424    425         elif isinstance(n, compiler.ast.Not):   426             return self.process_not_node(n)   427    428         # Exception control-flow tracking.   429    430         elif isinstance(n, compiler.ast.TryExcept):   431             self.process_try_node(n)   432    433         elif isinstance(n, compiler.ast.TryFinally):   434             self.process_try_finally_node(n)   435    436         # Control-flow modification statements.   437    438         elif isinstance(n, compiler.ast.Break):   439             self.writestmt("break;")   440    441         elif isinstance(n, compiler.ast.Continue):   442             self.writestmt("continue;")   443    444         elif isinstance(n, compiler.ast.Raise):   445             self.process_raise_node(n)   446    447         elif isinstance(n, compiler.ast.Return):   448             return self.process_return_node(n)   449    450         # Print statements.   451    452         elif isinstance(n, (compiler.ast.Print, compiler.ast.Printnl)):   453             self.statement(self.process_print_node(n))   454    455         # Invocations.   456    457         elif isinstance(n, compiler.ast.CallFunc):   458             return self.process_invocation_node(n)   459    460         elif isinstance(n, compiler.ast.Keyword):   461             return self.process_structure_node(n.expr)   462    463         # Constant usage.   464    465         elif isinstance(n, compiler.ast.Const):   466             return self.get_literal_instance(n)   467    468         elif isinstance(n, compiler.ast.Dict):   469             return self.get_literal_instance(n, "dict")   470    471         elif isinstance(n, compiler.ast.List):   472             return self.get_literal_instance(n, "list")   473    474         elif isinstance(n, compiler.ast.Tuple):   475             return self.get_literal_instance(n, "tuple")   476    477         # All other nodes are processed depth-first.   478    479         else:   480             return self.process_structure(n)   481    482     def process_assignment_node(self, n, expr):   483    484         "Process the individual node 'n' to be assigned the contents of 'expr'."   485    486         # Names and attributes are assigned the entire expression.   487    488         if isinstance(n, compiler.ast.AssName):   489             name_ref = self.process_name_node(n, self.process_structure_node(expr))   490             self.statement(name_ref)   491    492             # Employ guards after assignments if required.   493    494             if expr and name_ref.is_name():   495                 self.generate_guard(name_ref.name)   496    497         elif isinstance(n, compiler.ast.AssAttr):   498             in_assignment = self.in_assignment   499             self.in_assignment = self.process_structure_node(expr)   500             self.statement(self.process_attribute_access(n))   501             self.in_assignment = in_assignment   502    503         # Lists and tuples are matched against the expression and their   504         # items assigned to expression items.   505    506         elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)):   507             self.process_assignment_node_items(n, expr)   508    509         # Slices and subscripts are permitted within assignment nodes.   510    511         elif isinstance(n, compiler.ast.Slice):   512             self.statement(self.process_slice_node(n, expr))   513    514         elif isinstance(n, compiler.ast.Subscript):   515             self.statement(self.process_subscript_node(n, expr))   516    517     def process_attribute_access(self, n):   518    519         "Process the given attribute access node 'n'."   520    521         # Obtain any completed chain and return the reference to it.   522    523         attr_expr = self.process_attribute_chain(n)   524         if self.have_access_expression(n):   525             return attr_expr   526    527         # Where the start of the chain of attributes has been reached, process   528         # the complete access.   529    530         name_ref = attr_expr and attr_expr.is_name() and attr_expr   531         name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref) or None   532    533         location = self.get_access_location(name, self.attrs)   534         refs = self.get_referenced_attributes(location)   535    536         # Generate access instructions.   537    538         subs = {   539             "<expr>" : attr_expr,   540             "<name>" : "%s.value" % attr_expr,   541             "<assexpr>" : self.in_assignment,   542             }   543    544         subs.update(self.temp_subs)   545         subs.update(self.op_subs)   546    547         output = []   548         substituted = set()   549    550         # The context set or retrieved will be that used by any enclosing   551         # invocation.   552    553         context_index = self.function_target - 1   554         context_identity = None   555    556         # Obtain encoded versions of each instruction, accumulating temporary   557         # variables.   558    559         for instruction in self.optimiser.access_instructions[location]:   560    561             # Intercept a special instruction identifying the context.   562    563             if instruction[0] == "<context_identity>":   564                 context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index)   565                 continue   566    567             # Collect the encoded instruction, noting any temporary variables   568             # required by it.   569    570             encoded, _substituted = encode_access_instruction(instruction, subs, context_index)   571             output.append(encoded)   572             substituted.update(_substituted)   573    574         # Record temporary name usage.   575    576         for sub in substituted:   577             if self.temp_subs.has_key(sub):   578                 self.record_temp(self.temp_subs[sub])   579    580         del self.attrs[0]   581         return AttrResult(output, refs, location, context_identity)   582    583     def init_substitutions(self):   584    585         """   586         Initialise substitutions, defining temporary variable mappings, some of   587         which are also used as substitutions, together with operation mappings   588         used as substitutions in instructions defined by the optimiser.   589         """   590    591         self.temp_subs = {   592    593             # Substitutions used by instructions.   594    595             "<private_context>" : "__tmp_private_context",   596             "<accessor>" : "__tmp_value",   597             "<target_accessor>" : "__tmp_target_value",   598    599             # Mappings to be replaced by those given below.   600    601             "<context>" : "__tmp_contexts",   602             "<test_context_revert>" : "__tmp_contexts",   603             "<test_context_static>" : "__tmp_contexts",   604             "<set_context>" : "__tmp_contexts",   605             "<set_private_context>" : "__tmp_private_context",   606             "<set_accessor>" : "__tmp_value",   607             "<set_target_accessor>" : "__tmp_target_value",   608             }   609    610         self.op_subs = {   611             "<context>" : "__get_context",   612             "<test_context_revert>" : "__test_context_revert",   613             "<test_context_static>" : "__test_context_static",   614             "<set_context>" : "__set_context",   615             "<set_private_context>" : "__set_private_context",   616             "<set_accessor>" : "__set_accessor",   617             "<set_target_accessor>" : "__set_target_accessor",   618             }   619    620     def get_referenced_attributes(self, location):   621    622         """   623         Convert 'location' to the form used by the deducer and retrieve any   624         identified attributes.   625         """   626    627         access_location = self.deducer.const_accesses.get(location)   628         refs = []   629         for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]:   630             refs.append(attr)   631         return refs   632    633     def get_referenced_attribute_invocations(self, location):   634    635         """   636         Convert 'location' to the form used by the deducer and retrieve any   637         identified attribute invocation details.   638         """   639    640         access_location = self.deducer.const_accesses.get(location)   641         return self.deducer.reference_invocations_unsuitable.get(access_location or location)   642    643     def get_accessor_kinds(self, location):   644    645         "Return the accessor kinds for 'location'."   646    647         return self.optimiser.accessor_kinds.get(location)   648    649     def get_access_location(self, name, attrnames=None):   650    651         """   652         Using the current namespace, the given 'name', and the 'attrnames'   653         employed in an access, return the access location.   654         """   655    656         path = self.get_path_for_access()   657    658         # Get the location used by the deducer and optimiser and find any   659         # recorded access.   660    661         attrnames = attrnames and ".".join(self.attrs)   662         access_number = self.get_access_number(path, name, attrnames)   663         self.update_access_number(path, name, attrnames)   664         return (path, name, attrnames, access_number)   665    666     def get_access_number(self, path, name, attrnames):   667         access = name, attrnames   668         if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access):   669             return self.attr_accesses[path][access]   670         else:   671             return 0   672    673     def update_access_number(self, path, name, attrnames):   674         access = name, attrnames   675         if name:   676             init_item(self.attr_accesses, path, dict)   677             init_item(self.attr_accesses[path], access, lambda: 0)   678             self.attr_accesses[path][access] += 1   679    680     def get_accessor_location(self, name):   681    682         """   683         Using the current namespace and the given 'name', return the accessor   684         location.   685         """   686    687         path = self.get_path_for_access()   688    689         # Get the location used by the deducer and optimiser and find any   690         # recorded accessor.   691    692         access_number = self.get_accessor_number(path, name)   693         self.update_accessor_number(path, name)   694         return (path, name, None, access_number)   695    696     def get_accessor_number(self, path, name):   697         if self.attr_accessors.has_key(path) and self.attr_accessors[path].has_key(name):   698             return self.attr_accessors[path][name]   699         else:   700             return 0   701    702     def update_accessor_number(self, path, name):   703         if name:   704             init_item(self.attr_accessors, path, dict)   705             init_item(self.attr_accessors[path], name, lambda: 0)   706             self.attr_accessors[path][name] += 1   707    708     def process_class_node(self, n):   709    710         "Process the given class node 'n'."   711    712         class_name = self.get_object_path(n.name)   713    714         # Where a class is set conditionally or where the name may refer to   715         # different values, assign the name.   716    717         ref = self.importer.identify(class_name)   718    719         if not ref.static():   720             self.process_assignment_for_object(n.name,   721                 make_expression("__ATTRVALUE(&%s)" % encode_path(class_name)))   722    723         self.enter_namespace(n.name)   724    725         if self.have_object():   726             self.write_comment("Class: %s" % class_name)   727    728             self.initialise_inherited_members(class_name)   729    730             self.process_structure(n)   731             self.write_comment("End class: %s" % class_name)   732    733         self.exit_namespace()   734    735     def initialise_inherited_members(self, class_name):   736    737         "Initialise members of 'class_name' inherited from its ancestors."   738    739         for name, path in self.importer.all_class_attrs[class_name].items():   740             target = "%s.%s" % (class_name, name)   741    742             # Ignore attributes with definitions.   743    744             ref = self.importer.identify(target)   745             if ref:   746                 continue   747    748             # Ignore special type attributes.   749    750             if is_type_attribute(name):   751                 continue   752    753             # Reference inherited attributes.   754    755             ref = self.importer.identify(path)   756             if ref and not ref.static():   757                 parent, attrname = path.rsplit(".", 1)   758    759                 self.writestmt("__store_via_object(&%s, %s, __load_via_object(&%s, %s));" % (   760                     encode_path(class_name), name,   761                     encode_path(parent), attrname   762                     ))   763    764     def process_from_node(self, n):   765    766         "Process the given node 'n', importing from another module."   767    768         path = self.get_namespace_path()   769    770         # Attempt to obtain the referenced objects.   771    772         for name, alias in n.names:   773             if name == "*":   774                 raise InspectError("Only explicitly specified names can be imported from modules.", path, n)   775    776             # Obtain the path of the assigned name.   777    778             objpath = self.get_object_path(alias or name)   779    780             # Obtain the identity of the name.   781    782             ref = self.importer.identify(objpath)   783    784             # Where the name is not static, assign the value.   785    786             if ref and not ref.static() and ref.get_name():   787                 self.writestmt("%s;" %    788                     TrResolvedNameRef(alias or name, Reference("<var>", None, objpath),   789                                       expr=TrResolvedNameRef(name, ref)))   790    791     def process_function_body_node(self, n):   792    793         """   794         Process the given function, lambda, if expression or list comprehension   795         node 'n', generating the body.   796         """   797    798         function_name = self.get_namespace_path()   799         self.start_function(function_name)   800    801         # Process the function body.   802    803         in_conditional = self.in_conditional   804         self.in_conditional = False   805         self.function_target = 0   806    807         # Process any guards defined for the parameters.   808    809         for name in self.importer.function_parameters.get(function_name):   810             self.generate_guard(name)   811    812         # Produce the body and any additional return statement.   813    814         expr = self.process_structure_node(n.code) or PredefinedConstantRef("None")   815         if not isinstance(expr, ReturnRef):   816             self.writestmt("return %s;" % expr)   817    818         self.in_conditional = in_conditional   819    820         self.end_function(function_name)   821    822     def generate_guard(self, name):   823    824         """   825         Get the accessor details for 'name', found in the current namespace, and   826         generate any guards defined for it.   827         """   828    829         # Obtain the location, keeping track of assignment versions.   830    831         location = self.get_accessor_location(name)   832         test = self.deducer.accessor_guard_tests.get(location)   833    834         # Generate any guard from the deduced information.   835    836         if test:   837             guard, guard_type = test   838    839             if guard == "specific":   840                 ref = first(self.deducer.accessor_all_types[location])   841                 argstr = "&%s" % encode_path(ref.get_origin())   842             elif guard == "common":   843                 ref = first(self.deducer.accessor_all_general_types[location])   844                 argstr = encode_path(encode_type_attribute(ref.get_origin()))   845             else:   846                 return   847    848             # Produce an appropriate access to an attribute's value.   849    850             parameters = self.importer.function_parameters.get(self.get_namespace_path())   851             if parameters and name in parameters:   852                 name_to_value = "%s->value" % name   853             else:   854                 name_to_value = "%s.value" % name   855    856             # Write a test that raises a TypeError upon failure.   857    858             self.writestmt("if (!__test_%s_%s(%s, %s)) __raise_type_error();" % (   859                 guard, guard_type, name_to_value, argstr))   860    861     def process_function_node(self, n):   862    863         """   864         Process the given function, lambda, if expression or list comprehension   865         node 'n', generating any initialisation statements.   866         """   867    868         # Where a function is declared conditionally, use a separate name for   869         # the definition, and assign the definition to the stated name.   870    871         original_name = n.name   872    873         if self.in_conditional or self.in_function:   874             name = self.get_lambda_name()   875         else:   876             name = n.name   877    878         objpath = self.get_object_path(name)   879    880         # Obtain details of the defaults.   881    882         defaults = self.process_function_defaults(n, name, objpath)   883         if defaults:   884             for default in defaults:   885                 self.writeline("%s;" % default)   886    887         # Where a function is set conditionally or where the name may refer to   888         # different values, assign the name.   889    890         ref = self.importer.identify(objpath)   891    892         if self.in_conditional or self.in_function:   893             self.process_assignment_for_object(original_name, compiler.ast.Name(name))   894         elif not ref.static():   895             context = self.is_method(objpath)   896    897             self.process_assignment_for_object(original_name,   898                 make_expression("__ATTRVALUE(&%s)" % encode_path(objpath)))   899    900     def process_function_defaults(self, n, name, objpath, instance_name=None):   901    902         """   903         Process the given function or lambda node 'n', initialising defaults   904         that are dynamically set. The given 'name' indicates the name of the   905         function. The given 'objpath' indicates the origin of the function.   906         The given 'instance_name' indicates the name of any separate instance   907         of the function created to hold the defaults.   908    909         Return a list of operations setting defaults on a function instance.   910         """   911    912         function_name = self.get_object_path(name)   913         function_defaults = self.importer.function_defaults.get(function_name)   914         if not function_defaults:   915             return None   916    917         # Determine whether any unidentified defaults are involved.   918    919         for argname, default in function_defaults:   920             if not default.static():   921                 break   922         else:   923             return None   924    925         # Handle bound methods.   926    927         if not instance_name:   928             instance_name = "&%s" % encode_path(objpath)   929    930         # Where defaults are involved but cannot be identified, obtain a new   931         # instance of the lambda and populate the defaults.   932    933         defaults = []   934    935         # Join the original defaults with the inspected defaults.   936    937         original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default]   938    939         for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)):   940    941             # Obtain any reference for the default.   942    943             if original:   944                 argname, default = original   945                 name_ref = self.process_structure_node(default)   946             elif inspected:   947                 argname, default = inspected   948                 name_ref = TrResolvedNameRef(argname, default)   949             else:   950                 continue   951    952             # Generate default initialisers except when constants are employed.   953             # Constants should be used when populating the function structures.   954    955             if name_ref and not isinstance(name_ref, TrConstantValueRef):   956                 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref))   957    958         return defaults   959    960     def process_if_node(self, n):   961    962         """   963         Process the given "if" node 'n'.   964         """   965    966         first = True   967         for test, body in n.tests:   968             test_ref = self.process_structure_node(test)   969             self.start_if(first, test_ref)   970    971             in_conditional = self.in_conditional   972             self.in_conditional = True   973             self.process_structure_node(body)   974             self.in_conditional = in_conditional   975    976             self.end_if()   977             first = False   978    979         if n.else_:   980             self.start_else()   981             self.process_structure_node(n.else_)   982             self.end_else()   983    984         print >>self.out   985    986     def process_invocation_node(self, n):   987    988         "Process the given invocation node 'n'."   989    990         # Any invocations in the expression will store target details in a   991         # different location.   992    993         self.function_target += 1   994    995         # Process the expression.   996    997         expr = self.process_structure_node(n.node)   998    999         # Reference the current target again.  1000   1001         self.function_target -= 1  1002   1003         # Obtain details of the invocation expression.  1004   1005         objpath = expr.get_origin()  1006         location = expr.access_location()  1007   1008         # Identified target details.  1009   1010         target = None  1011         target_structure = None  1012   1013         # Specific function target information.  1014   1015         function = None  1016   1017         # Instantiation involvement.  1018   1019         instantiation = False  1020         literal_instantiation = False  1021   1022         # Invocation requirements.  1023   1024         context_required = True  1025         have_access_context = isinstance(expr, AttrResult)  1026         context_identity = have_access_context and expr.context()  1027         parameters = None  1028   1029         # Obtain details of the callable and of its parameters.  1030   1031         # Literals may be instantiated specially.  1032   1033         if expr.is_name() and expr.name.startswith("$L") and objpath:  1034             instantiation = literal_instantiation = objpath  1035             target = encode_literal_instantiator(objpath)  1036             context_required = False  1037   1038         # Identified targets employ function pointers directly.  1039   1040         elif objpath:  1041             parameters = self.importer.function_parameters.get(objpath)  1042   1043             # Class invocation involves instantiators.  1044   1045             if expr.has_kind("<class>"):  1046                 instantiation = objpath  1047                 target = encode_instantiator_pointer(objpath)  1048                 init_ref = self.importer.all_class_attrs[objpath]["__init__"]  1049                 target_structure = "&%s" % encode_path(init_ref)  1050                 context_required = False  1051   1052             # Only plain functions and bound methods employ function pointers.  1053   1054             elif expr.has_kind("<function>"):  1055                 function = objpath  1056   1057                 # Test for functions and methods.  1058   1059                 context_required = self.is_method(objpath)  1060                 accessor_kinds = self.get_accessor_kinds(location)  1061                 instance_accessor = accessor_kinds and \  1062                                     len(accessor_kinds) == 1 and \  1063                                     first(accessor_kinds) == "<instance>"  1064   1065                 # Only identify certain bound methods or functions.  1066   1067                 if not context_required or instance_accessor:  1068                     target = encode_function_pointer(objpath)  1069   1070                 # Access bound method defaults even if it is not clear whether  1071                 # the accessor is appropriate.  1072   1073                 target_structure = "&%s" % encode_path(objpath)  1074   1075         # Other targets are retrieved at run-time. Some information about them  1076         # may be available and be used to provide warnings about argument  1077         # compatibility.  1078   1079         elif self.importer.give_warning("args"):  1080             unsuitable = self.get_referenced_attribute_invocations(location)  1081   1082             if unsuitable:  1083                 for ref in unsuitable:  1084                     _objpath = ref.get_origin()  1085                     num_parameters = len(self.importer.function_parameters[_objpath])  1086                     print >>sys.stderr, \  1087                         "In %s, at line %d, inappropriate number of " \  1088                         "arguments given. Need %d arguments to call %s." % (  1089                         self.get_namespace_path(), n.lineno, num_parameters,  1090                         _objpath)  1091   1092         # Determine any readily-accessible target identity.  1093   1094         target_identity = target or expr.is_name() and str(expr) or None  1095         target_var = target_identity or "__tmp_targets[%d]" % self.function_target  1096   1097         if not target_identity:  1098             self.record_temp("__tmp_targets")  1099   1100         if context_identity and context_identity.startswith("__tmp_contexts"):  1101             self.record_temp("__tmp_contexts")  1102   1103         # Arguments are presented in a temporary frame array with any context  1104         # always being the first argument. Where it would be unused, it may be  1105         # set to null.  1106   1107         if context_required:  1108             if have_access_context:  1109                 args = ["__ATTRVALUE(%s)" % context_identity]  1110             else:  1111                 args = ["__CONTEXT_AS_VALUE(%s)" % target_var]  1112         else:  1113             args = ["__NULL"]  1114   1115         # Complete the array with null values, permitting tests for a complete  1116         # set of arguments.  1117   1118         args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0)  1119         kwcodes = []  1120         kwargs = []  1121   1122         # Any invocations in the arguments will store target details in a  1123         # different location.  1124   1125         self.function_target += 1  1126   1127         for i, arg in enumerate(n.args):  1128             argexpr = self.process_structure_node(arg)  1129   1130             # Store a keyword argument, either in the argument list or  1131             # in a separate keyword argument list for subsequent lookup.  1132   1133             if isinstance(arg, compiler.ast.Keyword):  1134   1135                 # With knowledge of the target, store the keyword  1136                 # argument directly.  1137   1138                 if parameters:  1139                     try:  1140                         argnum = parameters.index(arg.name)  1141                     except ValueError:  1142                         raise TranslateError("Argument %s is not recognised." % arg.name,  1143                                              self.get_namespace_path(), n)  1144                     args[argnum+1] = str(argexpr)  1145   1146                 # Otherwise, store the details in a separate collection.  1147   1148                 else:  1149                     kwargs.append(str(argexpr))  1150                     kwcodes.append("{%s, %s}" % (  1151                         encode_ppos(arg.name), encode_pcode(arg.name)))  1152   1153             # Store non-keyword arguments in the argument list, rejecting  1154             # superfluous arguments.  1155   1156             else:  1157                 try:  1158                     args[i+1] = str(argexpr)  1159                 except IndexError:  1160                     raise TranslateError("Too many arguments specified.",  1161                                          self.get_namespace_path(), n)  1162   1163         # Reference the current target again.  1164   1165         self.function_target -= 1  1166   1167         # Defaults are added to the frame where arguments are missing.  1168   1169         if parameters:  1170             function_defaults = self.importer.function_defaults.get(objpath)  1171             if function_defaults:  1172   1173                 # Visit each default and set any missing arguments.  1174                 # Use the target structure to obtain defaults, as opposed to the  1175                 # actual function involved.  1176   1177                 for i, (argname, default) in enumerate(function_defaults):  1178                     argnum = parameters.index(argname)  1179                     if not args[argnum+1]:  1180                         args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i)  1181   1182         # Test for missing arguments.  1183   1184         if None in args:  1185             raise TranslateError("Not all arguments supplied.",  1186                                  self.get_namespace_path(), n)  1187   1188         # Encode the arguments.  1189   1190         argstr = "__ARGS(%s)" % ", ".join(args)  1191         kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0"  1192         kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0"  1193   1194         # Where literal instantiation is occurring, add an argument indicating  1195         # the number of values.  1196   1197         if literal_instantiation:  1198             argstr += ", %d" % (len(args) - 1)  1199   1200         # First, the invocation expression is presented.  1201   1202         stages = []  1203   1204         # Without a known specific callable, the expression provides the target.  1205   1206         if not target or context_required:  1207             if target:  1208                 if expr:  1209                     stages.append(str(expr))  1210             elif not target_identity:  1211                 stages.append("%s = %s" % (target_var, expr))  1212   1213         # Any specific callable is then obtained.  1214   1215         if target:  1216             stages.append(target)  1217   1218         # Methods accessed via unidentified accessors are obtained.   1219   1220         elif function:  1221             if context_required:  1222                 if have_access_context:  1223                     stages.append("__get_function(%s, %s)" % (  1224                         context_identity, target_var))  1225                 else:  1226                     stages.append("__get_function(__CONTEXT_AS_VALUE(%s).value, %s)" % (  1227                         target_var, target_var))  1228             else:  1229                 stages.append("__load_via_object(%s.value, __fn__).fn" % target_var)  1230   1231         # With a known target, the function is obtained directly and called.  1232         # By putting the invocation at the end of the final element in the  1233         # instruction sequence (the stages), the result becomes the result of  1234         # the sequence. Moreover, the parameters become part of the sequence  1235         # and thereby participate in a guaranteed evaluation order.  1236   1237         if target or function:  1238             stages[-1] += "(%s)" % argstr  1239             if instantiation:  1240                 return InstantiationResult(instantiation, stages)  1241             else:  1242                 return InvocationResult(stages)  1243   1244         # With unknown targets, the generic invocation function is applied to  1245         # the callable and argument collections.  1246   1247         else:  1248             stages.append("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % (  1249                 target_var,  1250                 self.always_callable and 1 or 0,  1251                 len(kwargs), kwcodestr, kwargstr,  1252                 len(args), argstr))  1253             return InvocationResult(stages)  1254   1255     def always_callable(self, refs):  1256   1257         "Determine whether all 'refs' are callable."  1258   1259         for ref in refs:  1260             if not ref.static():  1261                 return False  1262             else:  1263                 origin = ref.final()  1264                 if not self.importer.get_attribute(origin, "__fn__"):  1265                     return False  1266         return True  1267   1268     def need_default_arguments(self, objpath, nargs):  1269   1270         """  1271         Return whether any default arguments are needed when invoking the object  1272         given by 'objpath'.  1273         """  1274   1275         parameters = self.importer.function_parameters.get(objpath)  1276         return nargs < len(parameters)  1277   1278     def process_lambda_node(self, n):  1279   1280         "Process the given lambda node 'n'."  1281   1282         name = self.get_lambda_name()  1283         function_name = self.get_object_path(name)  1284   1285         defaults = self.process_function_defaults(n, name, function_name, "__tmp_value")  1286   1287         # Without defaults, produce an attribute referring to the function.  1288   1289         if not defaults:  1290             return make_expression("__ATTRVALUE(&%s)" % encode_path(function_name))  1291   1292         # With defaults, copy the function structure and set the defaults on the  1293         # copy.  1294   1295         else:  1296             self.record_temp("__tmp_value")  1297             return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, __ATTRVALUE(__tmp_value))" % (  1298                 encode_path(function_name),  1299                 encode_symbol("obj", function_name),  1300                 ", ".join(defaults)))  1301   1302     def process_logical_node(self, n):  1303   1304         "Process the given operator node 'n'."  1305   1306         self.record_temp("__tmp_result")  1307   1308         conjunction = isinstance(n, compiler.ast.And)  1309         results = []  1310   1311         for node in n.nodes:  1312             results.append(self.process_structure_node(node))  1313   1314         return LogicalOperationResult(results, conjunction)  1315   1316     def process_name_node(self, n, expr=None):  1317   1318         "Process the given name node 'n' with the optional assignment 'expr'."  1319   1320         # Determine whether the name refers to a static external entity.  1321   1322         if n.name in predefined_constants:  1323             return PredefinedConstantRef(n.name, expr)  1324   1325         # Convert literal references, operator function names, and print  1326         # function names to references.  1327   1328         elif n.name.startswith("$L") or n.name.startswith("$op") or \  1329              n.name.startswith("$print"):  1330   1331             ref, paths = self.importer.get_module(self.name).special[n.name]  1332             return TrResolvedNameRef(n.name, ref)  1333   1334         # Temporary names are output program locals.  1335   1336         elif n.name.startswith("$t"):  1337             return TrResolvedNameRef(n.name, Reference("<var>"), expr=expr)  1338   1339         # Get the appropriate name for the name reference, using the same method  1340         # as in the inspector.  1341   1342         path = self.get_namespace_path()  1343         objpath = self.get_object_path(n.name)  1344   1345         # Determine any assigned globals.  1346   1347         globals = self.importer.get_module(self.name).scope_globals.get(path)  1348   1349         # Explicitly declared globals.  1350   1351         if globals and n.name in globals:  1352             objpath = self.get_global_path(n.name)  1353             is_global = True  1354   1355         # Implicitly referenced globals in functions.  1356   1357         elif self.in_function:  1358             is_global = n.name not in self.importer.function_locals[path]  1359   1360         # Implicitly referenced globals elsewhere.  1361   1362         else:  1363             namespace = self.importer.identify(path)  1364             is_global = not self.importer.get_attributes(namespace, n.name)  1365   1366         # Get the static identity of the name.  1367   1368         ref = self.importer.identify(objpath)  1369         if ref and not ref.get_name():  1370             ref = ref.alias(objpath)  1371   1372         # Obtain any resolved names for non-assignment names.  1373   1374         if not expr and not ref and self.in_function:  1375             locals = self.importer.function_locals.get(path)  1376             ref = locals and locals.get(n.name)  1377   1378         # Determine whether the name refers to a parameter. The generation of  1379         # parameter references is different from other names.  1380   1381         parameters = self.importer.function_parameters.get(path)  1382         parameter = n.name == "self" and self.in_method() or \  1383                     parameters and n.name in parameters  1384   1385         # Find any invocation details.  1386   1387         location = self.get_access_location(n.name)  1388   1389         # Qualified names are used for resolved static references or for  1390         # static namespace members. The reference should be configured to return  1391         # such names.  1392   1393         return TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, parameter=parameter, location=location)  1394   1395     def process_not_node(self, n):  1396   1397         "Process the given operator node 'n'."  1398   1399         return self.make_negation(self.process_structure_node(n.expr))  1400   1401     def process_raise_node(self, n):  1402   1403         "Process the given raise node 'n'."  1404   1405         # NOTE: Determine which raise statement variants should be permitted.  1406   1407         if n.expr1:  1408   1409             # Names with accompanying arguments are treated like invocations.  1410   1411             if n.expr2:  1412                 call = compiler.ast.CallFunc(n.expr1, [n.expr2])  1413                 exc = self.process_structure_node(call)  1414                 self.writestmt("__Raise(%s);" % exc)  1415   1416             # Raise instances, testing the kind at run-time if necessary and  1417             # instantiating any non-instance.  1418   1419             else:  1420                 exc = self.process_structure_node(n.expr1)  1421   1422                 if isinstance(exc, TrInstanceRef):  1423                     self.writestmt("__Raise(%s);" % exc)  1424                 else:  1425                     self.writestmt("__Raise(__ensure_instance(%s));" % exc)  1426         else:  1427             self.writestmt("__Throw(__tmp_exc);")  1428   1429     def process_return_node(self, n):  1430   1431         "Process the given return node 'n'."  1432   1433         expr = self.process_structure_node(n.value) or PredefinedConstantRef("None")  1434         if self.in_try_finally or self.in_try_except:  1435             self.writestmt("__Return(%s);" % expr)  1436         else:  1437             self.writestmt("return %s;" % expr)  1438   1439         return ReturnRef()  1440   1441     def process_try_node(self, n):  1442   1443         """  1444         Process the given "try...except" node 'n'.  1445         """  1446   1447         in_try_except = self.in_try_except  1448         self.in_try_except = True  1449   1450         # Use macros to implement exception handling.  1451   1452         self.writestmt("__Try")  1453         self.writeline("{")  1454         self.indent += 1  1455         self.process_structure_node(n.body)  1456   1457         # Put the else statement in another try block that handles any raised  1458         # exceptions and converts them to exceptions that will not be handled by  1459         # the main handling block.  1460   1461         if n.else_:  1462             self.writestmt("__Try")  1463             self.writeline("{")  1464             self.indent += 1  1465             self.process_structure_node(n.else_)  1466             self.indent -= 1  1467             self.writeline("}")  1468             self.writeline("__Catch (__tmp_exc)")  1469             self.writeline("{")  1470             self.indent += 1  1471             self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);")  1472             self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);")  1473             self.indent -= 1  1474             self.writeline("}")  1475   1476         # Complete the try block and enter the finally block, if appropriate.  1477   1478         if self.in_try_finally:  1479             self.writestmt("__Complete;")  1480   1481         self.indent -= 1  1482         self.writeline("}")  1483   1484         self.in_try_except = in_try_except  1485   1486         # Handlers are tests within a common handler block.  1487   1488         self.writeline("__Catch (__tmp_exc)")  1489         self.writeline("{")  1490         self.indent += 1  1491   1492         # Introduce an if statement to handle the completion of a try block.  1493   1494         self.process_try_completion()  1495   1496         # Handle exceptions in else blocks converted to __RaiseElse, converting  1497         # them back to normal exceptions.  1498   1499         if n.else_:  1500             self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);")  1501   1502         # Exception handling.  1503   1504         for name, var, handler in n.handlers:  1505   1506             # Test for specific exceptions.  1507   1508             if name is not None:  1509                 name_ref = self.process_structure_node(name)  1510                 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref)  1511             else:  1512                 self.writeline("else if (1)")  1513   1514             self.writeline("{")  1515             self.indent += 1  1516   1517             # Establish the local for the handler.  1518   1519             if var is not None:  1520                 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg")))  1521   1522             if handler is not None:  1523                 self.process_structure_node(handler)  1524   1525             self.indent -= 1  1526             self.writeline("}")  1527   1528         # Re-raise unhandled exceptions.  1529   1530         self.writeline("else __Throw(__tmp_exc);")  1531   1532         # End the handler block.  1533   1534         self.indent -= 1  1535         self.writeline("}")  1536         print >>self.out  1537   1538     def process_try_finally_node(self, n):  1539   1540         """  1541         Process the given "try...finally" node 'n'.  1542         """  1543   1544         in_try_finally = self.in_try_finally  1545         self.in_try_finally = True  1546   1547         # Use macros to implement exception handling.  1548   1549         self.writestmt("__Try")  1550         self.writeline("{")  1551         self.indent += 1  1552         self.process_structure_node(n.body)  1553         self.indent -= 1  1554         self.writeline("}")  1555   1556         self.in_try_finally = in_try_finally  1557   1558         # Finally clauses handle special exceptions.  1559   1560         self.writeline("__Catch (__tmp_exc)")  1561         self.writeline("{")  1562         self.indent += 1  1563         self.process_structure_node(n.final)  1564   1565         # Introduce an if statement to handle the completion of a try block.  1566   1567         self.process_try_completion()  1568         self.writeline("else __Throw(__tmp_exc);")  1569   1570         self.indent -= 1  1571         self.writeline("}")  1572         print >>self.out  1573   1574     def process_try_completion(self):  1575   1576         "Generate a test for the completion of a try block."  1577   1578         self.writestmt("if (__tmp_exc.completing)")  1579         self.writeline("{")  1580         self.indent += 1  1581   1582         # Do not return anything at the module level.  1583   1584         if self.get_namespace_path() != self.name:  1585   1586             # Only use the normal return statement if no surrounding try blocks  1587             # apply.  1588   1589             if not self.in_try_finally and not self.in_try_except:  1590                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;")  1591             else:  1592                 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);")  1593   1594         self.indent -= 1  1595         self.writeline("}")  1596   1597     def process_while_node(self, n):  1598   1599         "Process the given while node 'n'."  1600   1601         self.writeline("while (1)")  1602         self.writeline("{")  1603         self.indent += 1  1604         test = self.process_structure_node(n.test)  1605   1606         # Emit the loop termination condition unless "while <true value>" is  1607         # indicated.  1608   1609         if not (isinstance(test, PredefinedConstantRef) and test.value):  1610   1611             # Emit a negated test of the continuation condition.  1612   1613             self.start_if(True, self.make_negation(test))  1614             if n.else_:  1615                 self.process_structure_node(n.else_)  1616             self.writestmt("break;")  1617             self.end_if()  1618   1619         in_conditional = self.in_conditional  1620         self.in_conditional = True  1621         self.process_structure_node(n.body)  1622         self.in_conditional = in_conditional  1623   1624         self.indent -= 1  1625         self.writeline("}")  1626         print >>self.out  1627   1628     # Special variable usage.  1629   1630     def get_temp_path(self):  1631   1632         """  1633         Return the appropriate namespace path for temporary names in the current  1634         namespace.  1635         """  1636   1637         if self.in_function:  1638             return self.get_namespace_path()  1639         else:  1640             return self.name  1641   1642     def record_temp(self, name):  1643   1644         """  1645         Record the use of the temporary 'name' in the current namespace. At the  1646         class or module level, the temporary name is associated with the module,  1647         since the variable will then be allocated in the module's own main  1648         program.  1649         """  1650   1651         path = self.get_temp_path()  1652   1653         init_item(self.temp_usage, path, list)  1654         self.temp_usage[path].append(name)  1655   1656     def remove_temps(self, names):  1657   1658         """  1659         Remove 'names' from temporary storage allocations, each instance  1660         removing each request for storage.  1661         """  1662   1663         path = self.get_temp_path()  1664   1665         for name in names:  1666             if self.uses_temp(path, name):  1667                 self.temp_usage[path].remove(name)  1668   1669     def uses_temp(self, path, name):  1670   1671         """  1672         Return whether the given namespace 'path' employs a temporary variable  1673         with the given 'name'. Note that 'path' should only be a module or a  1674         function or method, not a class.  1675         """  1676   1677         return self.temp_usage.has_key(path) and name in self.temp_usage[path]  1678   1679     def make_negation(self, expr):  1680   1681         "Return a negated form of 'expr'."  1682   1683         result = NegationResult(expr)  1684   1685         # Negation discards the temporary results of its operand.  1686   1687         temps = expr.discards_temporary()  1688         if temps:  1689             self.remove_temps(temps)  1690   1691         return result  1692   1693     # Output generation.  1694   1695     def start_output(self):  1696   1697         "Write the declarations at the top of each source file."  1698   1699         print >>self.out, """\  1700 #include "types.h"  1701 #include "exceptions.h"  1702 #include "ops.h"  1703 #include "progconsts.h"  1704 #include "progops.h"  1705 #include "progtypes.h"  1706 #include "main.h"  1707 """  1708   1709     def start_unit(self):  1710   1711         "Record output within a generated function for later use."  1712   1713         self.out = StringIO()  1714   1715     def end_unit(self, name):  1716   1717         "Add declarations and generated code."  1718   1719         # Restore the output stream.  1720   1721         out = self.out  1722         self.out = self.out_toplevel  1723   1724         self.write_temporaries(name)  1725         print >>self.out  1726         out.seek(0)  1727         self.out.write(out.read())  1728   1729         self.indent -= 1  1730         print >>self.out, "}"  1731   1732     def start_module(self):  1733   1734         "Write the start of each module's main function."  1735   1736         print >>self.out, "void __main_%s()" % encode_path(self.name)  1737         print >>self.out, "{"  1738         self.indent += 1  1739   1740         # Define temporary variables, excluded from the module structure itself.  1741   1742         tempnames = []  1743   1744         for n in self.importer.all_module_attrs[self.name]:  1745             if n.startswith("$t"):  1746                 tempnames.append(encode_path(n))  1747   1748         if tempnames:  1749             tempnames.sort()  1750             self.writeline("__attr %s;" % ", ".join(tempnames))  1751   1752         self.start_unit()  1753   1754     def end_module(self):  1755   1756         "End each module by closing its main function."  1757   1758         self.end_unit(self.name)  1759   1760     def start_function(self, name):  1761   1762         "Start the function having the given 'name'."  1763   1764         print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name)  1765         print >>self.out, "{"  1766         self.indent += 1  1767   1768         # Obtain local names from parameters.  1769   1770         parameters = self.importer.function_parameters[name]  1771         locals = self.importer.function_locals[name].keys()  1772         names = []  1773   1774         for n in locals:  1775   1776             # Filter out special names and parameters. Note that self is a local  1777             # regardless of whether it originally appeared in the parameters or  1778             # not.  1779   1780             if n.startswith("$l") or n in parameters or n == "self":  1781                 continue  1782             names.append(encode_path(n))  1783   1784         # Emit required local names.  1785   1786         if names:  1787             names.sort()  1788             self.writeline("__attr %s;" % ", ".join(names))  1789   1790         self.write_parameters(name)  1791         self.start_unit()  1792   1793     def end_function(self, name):  1794   1795         "End the function having the given 'name'."  1796   1797         self.end_unit(name)  1798         print >>self.out  1799   1800     def write_temporaries(self, name):  1801   1802         "Write temporary storage employed by 'name'."  1803   1804         # Provide space for the given number of targets.  1805   1806         targets = self.importer.function_targets.get(name)  1807   1808         if self.uses_temp(name, "__tmp_targets"):  1809             self.writeline("__attr __tmp_targets[%d];" % targets)  1810         if self.uses_temp(name, "__tmp_contexts"):  1811             self.writeline("__ref __tmp_contexts[%d];" % targets)  1812   1813         # Add temporary variable usage details.  1814   1815         if self.uses_temp(name, "__tmp_private_context"):  1816             self.writeline("__ref __tmp_private_context;")  1817         if self.uses_temp(name, "__tmp_value"):  1818             self.writeline("__ref __tmp_value;")  1819         if self.uses_temp(name, "__tmp_target_value"):  1820             self.writeline("__ref __tmp_target_value;")  1821         if self.uses_temp(name, "__tmp_result"):  1822             self.writeline("__attr __tmp_result;")  1823   1824         module = self.importer.get_module(self.name)  1825   1826         if name in module.exception_namespaces:  1827             self.writeline("__exc __tmp_exc;")  1828   1829     def write_parameters(self, name):  1830   1831         """  1832         For the function having the given 'name', write definitions of  1833         parameters found in the arguments array.  1834         """  1835   1836         parameters = self.importer.function_parameters[name]  1837   1838         # Generate any self reference.  1839   1840         if self.is_method(name):  1841             self.writeline("__attr * const self = &__args[0];")  1842   1843         # Generate aliases for the parameters.  1844   1845         for i, parameter in enumerate(parameters):  1846             self.writeline("__attr * const %s = &__args[%d];" % (encode_path(parameter), i+1))  1847   1848     def start_if(self, first, test_ref):  1849         statement = "%sif" % (not first and "else " or "")  1850   1851         # Consume logical results directly.  1852   1853         if isinstance(test_ref, LogicalResult):  1854             self.writeline("%s %s" % (statement, test_ref.apply_test()))  1855             temps = test_ref.discards_temporary()  1856             if temps:  1857                 self.remove_temps(temps)  1858         else:  1859             self.writeline("%s (__BOOL(%s))" % (statement, test_ref))  1860   1861         self.writeline("{")  1862         self.indent += 1  1863   1864     def end_if(self):  1865         self.indent -= 1  1866         self.writeline("}")  1867   1868     def start_else(self):  1869         self.writeline("else")  1870         self.writeline("{")  1871         self.indent += 1  1872   1873     def end_else(self):  1874         self.indent -= 1  1875         self.writeline("}")  1876   1877     def statement(self, expr):  1878         s = str(expr)  1879         if s:  1880             self.writestmt("%s;" % s)  1881   1882     def statements(self, results):  1883         for result in results:  1884             self.statement(result)  1885   1886     def writeline(self, s):  1887         print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1))  1888   1889     def writestmt(self, s):  1890         self.writeline(s)  1891   1892     def write_comment(self, s):  1893         self.writestmt("/* %s */" % s)  1894   1895     def pad(self, extra=0):  1896         return (self.indent + extra) * self.tabstop  1897   1898     def indenttext(self, s, levels):  1899         lines = s.split("\n")  1900         out = [lines[0]]  1901         for line in lines[1:]:  1902             out.append(levels * self.tabstop + line)  1903             if line.endswith("("):  1904                 levels += 1  1905             elif line.startswith(")"):  1906                 levels -= 1  1907         return "\n".join(out)  1908   1909 # vim: tabstop=4 expandtab shiftwidth=4