Lichen

transresults.py

682:f355f9f6647c
2017-03-08 Paul Boddie Merged changes from the default branch. normal-function-parameters
     1 #!/usr/bin/env python     2      3 """     4 Translation result abstractions.     5      6 Copyright (C) 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 first, InstructionSequence    23 from encoders import encode_instructions, encode_literal_constant, encode_path    24 from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, \    25                     ResolvedNameRef, Result    26     27 # Classes representing intermediate translation results.    28     29 class ReturnRef:    30     31     "Indicates usage of a return statement."    32     33     pass    34     35 class Expression(Result):    36     37     "A general expression."    38     39     def __init__(self, s):    40         if isinstance(s, Result):    41             self.s = str(s)    42             self.expr = s    43         else:    44             self.s = s    45             self.expr = None    46     47     def discards_temporary(self, test=True):    48     49         """    50         Return a list of temporary names that can be discarded if 'test' is    51         specified as a true value (or omitted).    52         """    53     54         return self.expr and self.expr.discards_temporary(False)    55     56     def __str__(self):    57         return self.s    58     59     def __repr__(self):    60         return "Expression(%r)" % self.s    61     62 class TrResolvedNameRef(ResolvedNameRef):    63     64     "A reference to a name in the translation."    65     66     def __init__(self, name, ref, expr=None, is_global=False, location=None):    67         ResolvedNameRef.__init__(self, name, ref, expr, is_global)    68         self.location = location    69     70     def access_location(self):    71         return self.location    72     73     def __str__(self):    74     75         "Return an output representation of the referenced name."    76     77         # For sources, any identified static origin will be constant and thus    78         # usable directly. For targets, no constant should be assigned and thus    79         # the alias (or any plain name) will be used.    80     81         ref = self.static()    82         origin = ref and self.get_origin()    83         static_name = origin and encode_path(origin)    84     85         # Determine whether a qualified name is involved.    86     87         t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1)    88         parent = len(t) > 1 and t[0] or None    89         attrname = t[-1] and encode_path(t[-1])    90     91         # Assignments.    92     93         if self.expr:    94     95             # Eliminate assignments between constants.    96     97             if ref and isinstance(self.expr, ResolvedNameRef) and self.expr.static():    98                 return ""    99    100             # Qualified names must be converted into parent-relative assignments.   101    102             elif parent:   103                 return "__store_via_object(&%s, %s, %s)" % (   104                     encode_path(parent), attrname, self.expr)   105    106             # All other assignments involve the names as they were given.   107    108             else:   109                 return "%s = %s" % (attrname, self.expr)   110    111         # Expressions.   112    113         elif static_name:   114             parent = ref.parent()   115             context = ref.has_kind("<function>") and encode_path(parent) or None   116             return "__ATTRVALUE(&%s)" % static_name   117    118         # Qualified names must be converted into parent-relative accesses.   119    120         elif parent:   121             return "__load_via_object(&%s, %s)" % (   122                 encode_path(parent), attrname)   123    124         # All other accesses involve the names as they were given.   125    126         else:   127             return "(%s)" % attrname   128    129 class TrConstantValueRef(ConstantValueRef):   130    131     "A constant value reference in the translation."   132    133     def __str__(self):   134         return encode_literal_constant(self.number)   135    136 class TrLiteralSequenceRef(LiteralSequenceRef):   137    138     "A reference representing a sequence of values."   139    140     def __str__(self):   141         return str(self.node)   142    143 class TrInstanceRef(InstanceRef):   144    145     "A reference representing instantiation of a class."   146    147     def __init__(self, ref, expr):   148    149         """   150         Initialise the reference with 'ref' indicating the nature of the   151         reference and 'expr' being an expression used to create the instance.   152         """   153    154         InstanceRef.__init__(self, ref)   155         self.expr = expr   156    157     def __str__(self):   158         return self.expr   159    160     def __repr__(self):   161         return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)   162    163 class AttrResult(Result, InstructionSequence):   164    165     "A translation result for an attribute access."   166    167     def __init__(self, instructions, refs, location, context_identity):   168         InstructionSequence.__init__(self, instructions)   169         self.refs = refs   170         self.location = location   171         self.context_identity = context_identity   172    173     def references(self):   174         return self.refs   175    176     def access_location(self):   177         return self.location   178    179     def context(self):   180         return self.context_identity   181    182     def get_origin(self):   183         return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()   184    185     def has_kind(self, kinds):   186         if not self.refs:   187             return False   188         for ref in self.refs:   189             if ref.has_kind(kinds):   190                 return True   191         return False   192    193     def __nonzero__(self):   194         return bool(self.instructions)   195    196     def __str__(self):   197         return encode_instructions(self.instructions)   198    199     def __repr__(self):   200         return "AttrResult(%r, %r, %r)" % (self.instructions, self.refs, self.location)   201    202 class InvocationResult(Result, InstructionSequence):   203    204     "A translation result for an invocation."   205    206     def __str__(self):   207         return encode_instructions(self.instructions)   208    209     def __repr__(self):   210         return "InvocationResult(%r)" % self.instructions   211    212 class InstantiationResult(InvocationResult, TrInstanceRef):   213    214     "An instantiation result acting like an invocation result."   215    216     def __init__(self, ref, instructions):   217         InstanceRef.__init__(self, ref)   218         InvocationResult.__init__(self, instructions)   219    220     def __repr__(self):   221         return "InstantiationResult(%r, %r)" % (self.ref, self.instructions)   222    223 class PredefinedConstantRef(Result):   224    225     "A predefined constant reference."   226    227     def __init__(self, value, expr=None):   228         self.value = value   229         self.expr = expr   230    231     def __str__(self):   232    233         # Eliminate predefined constant assignments.   234    235         if self.expr:   236             return ""   237    238         # Generate the specific constants.   239    240         if self.value in ("False", "True"):   241             return encode_path("__builtins__.boolean.%s" % self.value)   242         elif self.value == "None":   243             return encode_path("__builtins__.none.%s" % self.value)   244         elif self.value == "NotImplemented":   245             return encode_path("__builtins__.notimplemented.%s" % self.value)   246         else:   247             return self.value   248    249     def __repr__(self):   250         return "PredefinedConstantRef(%r)" % self.value   251    252 class LogicalResult(Result):   253    254     "A logical expression result."   255    256     def _convert(self, expr):   257    258         "Return 'expr' converted to a testable value."   259    260         if isinstance(expr, LogicalResult):   261             return expr.apply_test()   262         else:   263             return "__BOOL(%s)" % expr   264    265 class NegationResult(LogicalResult):   266    267     "A negation expression result."   268    269     def __init__(self, expr):   270         self.expr = expr   271    272     def apply_test(self):   273    274         "Return the result in a form suitable for direct testing."   275    276         expr = self._convert(self.expr)   277         return "(!%s)" % expr   278    279     def discards_temporary(self, test=True):   280    281         """   282         Negations should have discarded their operand's temporary names when   283         being instantiated.   284         """   285    286         return None   287    288     def __str__(self):   289         return "(%s ? %s : %s)" % (   290             self._convert(self.expr),   291             PredefinedConstantRef("False"),   292             PredefinedConstantRef("True"))   293    294     def __repr__(self):   295         return "NegationResult(%r)" % self.expr   296    297 class LogicalOperationResult(LogicalResult):   298    299     "A logical operation result."   300    301     def __init__(self, exprs, conjunction):   302         self.exprs = exprs   303         self.conjunction = conjunction   304    305     def apply_test(self):   306    307         """   308         Return the result in a form suitable for direct testing.   309    310         Convert ... to ...   311    312         <a> and <b>   313         ((__BOOL(<a>)) && (__BOOL(<b>)))   314    315         <a> or <b>   316         ((__BOOL(<a>)) || (__BOOL(<b>)))   317         """   318    319         results = []   320         for expr in self.exprs:   321             results.append(self._convert(expr))   322    323         if self.conjunction:   324             return "(%s)" % " && ".join(results)   325         else:   326             return "(%s)" % " || ".join(results)   327    328     def discards_temporary(self, test=True):   329    330         """   331         Return a list of temporary names that can be discarded if 'test' is   332         specified as a true value (or omitted).   333         """   334    335         if not test:   336             return None   337    338         temps = ["__tmp_result"]   339    340         for expr in self.exprs:   341             t = expr.discards_temporary(test)   342             if t:   343                 temps += t   344    345         return temps   346    347     def __str__(self):   348    349         """   350         Convert ... to ...   351    352         <a> and <b>   353         (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b>   354    355         <a> or <b>   356         (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b>   357         """   358    359         results = []   360         for expr in self.exprs[:-1]:   361             results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, self.conjunction and "!" or ""))   362         results.append(str(self.exprs[-1]))   363    364         return "(%s)" % "".join(results)   365    366     def __repr__(self):   367         return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)   368    369 # vim: tabstop=4 expandtab shiftwidth=4