Lichen

translator.py

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