Lichen

transresults.py

947:329e5533b106
2021-11-04 Paul Boddie Store integers and floating point values as trailing data. Although not yet implemented, the idea is to reference them using tagged address attributes, and then to eventually support the copying of these values. tagged-address-values
     1 #!/usr/bin/env python     2      3 """     4 Translation result abstractions.     5      6 Copyright (C) 2016, 2017, 2018, 2021 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, NameRef, \    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         # Temporary names are output program locals.    78     79         if self.name.startswith("$t"):    80             if self.expr:    81                 return "%s = %s" % (encode_path(self.name), self.expr)    82             else:    83                 return encode_path(self.name)    84     85         # For sources, any identified static origin will be constant and thus    86         # usable directly. For targets, no constant should be assigned and thus    87         # the alias (or any plain name) will be used.    88     89         ref = self.static()    90         origin = ref and self.get_origin()    91         static_name = origin and encode_path(origin)    92     93         # Determine whether a qualified name is involved.    94     95         t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1)    96         parent = len(t) > 1 and t[0] or None    97         attrname = t[-1] and encode_path(t[-1])    98     99         # Assignments.   100    101         if self.expr:   102    103             # Eliminate assignments between constants.   104    105             if ref and self.expr.static():   106                 return ""   107    108             # Qualified names must be converted into parent-relative assignments.   109    110             elif parent:   111                 return "__store_via_object(&%s, %s, %s)" % (   112                     encode_path(parent), attrname, self.expr)   113    114             # All other assignments involve the names as they were given.   115    116             else:   117                 return "%s = %s" % (attrname, self.expr)   118    119         # Expressions.   120    121         elif static_name:   122             parent = ref.parent()   123             context = ref.has_kind("<function>") and encode_path(parent) or None   124             return "__ATTRVALUE(&%s)" % static_name   125    126         # Qualified names must be converted into parent-relative accesses.   127    128         elif parent:   129             return "__load_via_object(&%s, %s)" % (   130                 encode_path(parent), attrname)   131    132         # All other accesses involve the names as they were given.   133    134         else:   135             return "(%s)" % attrname   136    137 class TrConstantValueRef(ConstantValueRef):   138    139     "A constant value reference in the translation."   140    141     def __str__(self):   142         return encode_literal_constant(self.number)   143    144 class TrLiteralSequenceRef(LiteralSequenceRef):   145    146     "A reference representing a sequence of values."   147    148     def __str__(self):   149         return str(self.node)   150    151 class TrInstanceRef(InstanceRef):   152    153     "A reference representing instantiation of a class."   154    155     def __init__(self, ref, expr):   156    157         """   158         Initialise the reference with 'ref' indicating the nature of the   159         reference and 'expr' being an expression used to create the instance.   160         """   161    162         InstanceRef.__init__(self, ref)   163         self.expr = expr   164    165     def __str__(self):   166         return self.expr   167    168     def __repr__(self):   169         return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)   170    171 class AttrResult(Result, InstructionSequence):   172    173     "A translation result for an attribute access."   174    175     def __init__(self, instructions, refs, location, context_identity,   176                  context_identity_verified, accessor_test, accessor_stored):   177    178         InstructionSequence.__init__(self, instructions)   179         self.refs = refs   180         self.location = location   181         self.context_identity = context_identity   182         self.context_identity_verified = context_identity_verified   183         self.accessor_test = accessor_test   184         self.accessor_stored = accessor_stored   185    186     def references(self):   187         return self.refs   188    189     def access_location(self):   190         return self.location   191    192     def context(self):   193         return self.context_identity   194    195     def context_verified(self):   196         return self.context_identity_verified and self.context() or None   197    198     def tests_accessor(self):   199         return self.accessor_test   200    201     def stores_accessor(self):   202         return self.accessor_stored   203    204     def get_origin(self):   205         return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()   206    207     def has_kind(self, kinds):   208         if not self.refs:   209             return False   210         for ref in self.refs:   211             if ref.has_kind(kinds):   212                 return True   213         return False   214    215     def __nonzero__(self):   216         return bool(self.instructions)   217    218     def __str__(self):   219         return encode_instructions(self.instructions)   220    221     def __repr__(self):   222         return "AttrResult(%r, %r, %r, %r, %r, %r, %r)" % (   223                 self.instructions, self.refs, self.location,   224                 self.context_identity, self.context_identity_verified,   225                 self.accessor_test, self.accessor_stored)   226    227 class AliasResult(NameRef, Result):   228    229     "An alias for other values."   230    231     def __init__(self, name_ref, refs, location):   232         NameRef.__init__(self, name_ref.name, is_global=name_ref.is_global_name())   233         self.name_ref = name_ref   234         self.refs = refs   235         self.location = location   236    237     def references(self):   238         ref = self.name_ref.reference()   239         return self.refs or ref and [ref] or None   240    241     def reference(self):   242         refs = self.references()   243         return len(refs) == 1 and first(refs) or None   244    245     def access_location(self):   246         return self.location   247    248     def get_name(self):   249         ref = self.reference()   250         return ref and ref.get_name()   251    252     def get_origin(self):   253         ref = self.reference()   254         return ref and ref.get_origin()   255    256     def static(self):   257         ref = self.reference()   258         return ref and ref.static()   259    260     def final(self):   261         ref = self.reference()   262         return ref and ref.final()   263    264     def has_kind(self, kinds):   265         if not self.refs:   266             return self.name_ref.has_kind(kinds)   267    268         for ref in self.refs:   269             if ref.has_kind(kinds):   270                 return True   271    272         return False   273    274     def __str__(self):   275         return str(self.name_ref)   276    277     def __repr__(self):   278         return "AliasResult(%r, %r)" % (self.name_ref, self.refs)   279    280 class InvocationResult(Result, InstructionSequence):   281    282     "A translation result for an invocation."   283    284     def __str__(self):   285         return encode_instructions(self.instructions)   286    287     def __repr__(self):   288         return "InvocationResult(%r)" % self.instructions   289    290 class InstantiationResult(InvocationResult, TrInstanceRef):   291    292     "An instantiation result acting like an invocation result."   293    294     def __init__(self, ref, instructions):   295         InstanceRef.__init__(self, ref)   296         InvocationResult.__init__(self, instructions)   297    298     def __repr__(self):   299         return "InstantiationResult(%r, %r)" % (self.ref, self.instructions)   300    301 class PredefinedConstantRef(Result):   302    303     "A predefined constant reference."   304    305     def __init__(self, value, expr=None):   306         self.value = value   307         self.expr = expr   308    309     def __str__(self):   310    311         # Eliminate predefined constant assignments.   312    313         if self.expr:   314             return ""   315    316         # Generate the specific constants.   317    318         if self.value in ("False", "True"):   319             return encode_path("__builtins__.boolean.%s" % self.value)   320         elif self.value == "None":   321             return encode_path("__builtins__.none.%s" % self.value)   322         elif self.value == "NotImplemented":   323             return encode_path("__builtins__.notimplemented.%s" % self.value)   324         else:   325             return self.value   326    327     def __repr__(self):   328         return "PredefinedConstantRef(%r)" % self.value   329    330 class LogicalResult(Result):   331    332     "A logical expression result."   333    334     def _convert(self, expr):   335    336         "Return 'expr' converted to a testable value."   337    338         if isinstance(expr, LogicalResult):   339             return expr.apply_test()   340         else:   341             return "__BOOL(%s)" % expr   342    343 class NegationResult(LogicalResult):   344    345     "A negation expression result."   346    347     def __init__(self, expr):   348         self.expr = expr   349    350     def apply_test(self):   351    352         "Return the result in a form suitable for direct testing."   353    354         expr = self._convert(self.expr)   355         return "(!%s)" % expr   356    357     def discards_temporary(self, test=True):   358    359         """   360         Negations should have discarded their operand's temporary names when   361         being instantiated.   362         """   363    364         return None   365    366     def __str__(self):   367         return "(%s ? %s : %s)" % (   368             self._convert(self.expr),   369             PredefinedConstantRef("False"),   370             PredefinedConstantRef("True"))   371    372     def __repr__(self):   373         return "NegationResult(%r)" % self.expr   374    375 class LogicalOperationResult(LogicalResult):   376    377     "A logical operation result."   378    379     def __init__(self, exprs, conjunction):   380         self.exprs = exprs   381         self.conjunction = conjunction   382    383     def apply_test(self):   384    385         """   386         Return the result in a form suitable for direct testing.   387    388         Convert ... to ...   389    390         <a> and <b>   391         ((__BOOL(<a>)) && (__BOOL(<b>)))   392    393         <a> or <b>   394         ((__BOOL(<a>)) || (__BOOL(<b>)))   395         """   396    397         results = []   398         for expr in self.exprs:   399             results.append(self._convert(expr))   400    401         if self.conjunction:   402             return "(%s)" % " && ".join(results)   403         else:   404             return "(%s)" % " || ".join(results)   405    406     def discards_temporary(self, test=True):   407    408         """   409         Return a list of temporary names that can be discarded if 'test' is   410         specified as a true value (or omitted).   411         """   412    413         if not test:   414             return None   415    416         temps = ["__tmp_result"]   417    418         for expr in self.exprs:   419             t = expr.discards_temporary(test)   420             if t:   421                 temps += t   422    423         return temps   424    425     def __str__(self):   426    427         """   428         Convert ... to ...   429    430         <a> and <b>   431         (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b>   432    433         <a> or <b>   434         (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b>   435         """   436    437         results = []   438         for expr in self.exprs[:-1]:   439             results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, self.conjunction and "!" or ""))   440         results.append(str(self.exprs[-1]))   441    442         return "(%s)" % "".join(results)   443    444     def __repr__(self):   445         return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)   446    447 # vim: tabstop=4 expandtab shiftwidth=4