Lichen

transresults.py

948:6711c02b1d82
2021-11-05 Paul Boddie Removed superfluous statements.
     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             return "__ATTRVALUE(&%s)" % static_name   123    124         # Qualified names must be converted into parent-relative accesses.   125    126         elif parent:   127             return "__load_via_object(&%s, %s)" % (   128                 encode_path(parent), attrname)   129    130         # All other accesses involve the names as they were given.   131    132         else:   133             return "(%s)" % attrname   134    135 class TrConstantValueRef(ConstantValueRef):   136    137     "A constant value reference in the translation."   138    139     def __str__(self):   140    141         # NOTE: Should reference a common variable for the type name.   142    143         if self.ref.get_origin() == "__builtins__.int.int":   144             return "__INTVALUE(%s)" % self.value   145         else:   146             return encode_literal_constant(self.number)   147    148 class TrLiteralSequenceRef(LiteralSequenceRef):   149    150     "A reference representing a sequence of values."   151    152     def __str__(self):   153         return str(self.node)   154    155 class TrInstanceRef(InstanceRef):   156    157     "A reference representing instantiation of a class."   158    159     def __init__(self, ref, expr):   160    161         """   162         Initialise the reference with 'ref' indicating the nature of the   163         reference and 'expr' being an expression used to create the instance.   164         """   165    166         InstanceRef.__init__(self, ref)   167         self.expr = expr   168    169     def __str__(self):   170         return self.expr   171    172     def __repr__(self):   173         return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)   174    175 class AttrResult(Result, InstructionSequence):   176    177     "A translation result for an attribute access."   178    179     def __init__(self, instructions, refs, location, context_identity,   180                  context_identity_verified, accessor_test, accessor_stored):   181    182         InstructionSequence.__init__(self, instructions)   183         self.refs = refs   184         self.location = location   185         self.context_identity = context_identity   186         self.context_identity_verified = context_identity_verified   187         self.accessor_test = accessor_test   188         self.accessor_stored = accessor_stored   189    190     def references(self):   191         return self.refs   192    193     def access_location(self):   194         return self.location   195    196     def context(self):   197         return self.context_identity   198    199     def context_verified(self):   200         return self.context_identity_verified and self.context() or None   201    202     def tests_accessor(self):   203         return self.accessor_test   204    205     def stores_accessor(self):   206         return self.accessor_stored   207    208     def get_origin(self):   209         return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()   210    211     def has_kind(self, kinds):   212         if not self.refs:   213             return False   214         for ref in self.refs:   215             if ref.has_kind(kinds):   216                 return True   217         return False   218    219     def __nonzero__(self):   220         return bool(self.instructions)   221    222     def __str__(self):   223         return encode_instructions(self.instructions)   224    225     def __repr__(self):   226         return "AttrResult(%r, %r, %r, %r, %r, %r, %r)" % (   227                 self.instructions, self.refs, self.location,   228                 self.context_identity, self.context_identity_verified,   229                 self.accessor_test, self.accessor_stored)   230    231 class AliasResult(NameRef, Result):   232    233     "An alias for other values."   234    235     def __init__(self, name_ref, refs, location):   236         NameRef.__init__(self, name_ref.name, is_global=name_ref.is_global_name())   237         self.name_ref = name_ref   238         self.refs = refs   239         self.location = location   240    241     def references(self):   242         ref = self.name_ref.reference()   243         return self.refs or ref and [ref] or None   244    245     def reference(self):   246         refs = self.references()   247         return len(refs) == 1 and first(refs) or None   248    249     def access_location(self):   250         return self.location   251    252     def get_name(self):   253         ref = self.reference()   254         return ref and ref.get_name()   255    256     def get_origin(self):   257         ref = self.reference()   258         return ref and ref.get_origin()   259    260     def static(self):   261         ref = self.reference()   262         return ref and ref.static()   263    264     def final(self):   265         ref = self.reference()   266         return ref and ref.final()   267    268     def has_kind(self, kinds):   269         if not self.refs:   270             return self.name_ref.has_kind(kinds)   271    272         for ref in self.refs:   273             if ref.has_kind(kinds):   274                 return True   275    276         return False   277    278     def __str__(self):   279         return str(self.name_ref)   280    281     def __repr__(self):   282         return "AliasResult(%r, %r)" % (self.name_ref, self.refs)   283    284 class InvocationResult(Result, InstructionSequence):   285    286     "A translation result for an invocation."   287    288     def __str__(self):   289         return encode_instructions(self.instructions)   290    291     def __repr__(self):   292         return "InvocationResult(%r)" % self.instructions   293    294 class InstantiationResult(InvocationResult, TrInstanceRef):   295    296     "An instantiation result acting like an invocation result."   297    298     def __init__(self, ref, instructions):   299         InstanceRef.__init__(self, ref)   300         InvocationResult.__init__(self, instructions)   301    302     def __repr__(self):   303         return "InstantiationResult(%r, %r)" % (self.ref, self.instructions)   304    305 class PredefinedConstantRef(Result):   306    307     "A predefined constant reference."   308    309     def __init__(self, value, expr=None):   310         self.value = value   311         self.expr = expr   312    313     def __str__(self):   314    315         # Eliminate predefined constant assignments.   316    317         if self.expr:   318             return ""   319    320         # Generate the specific constants.   321    322         if self.value in ("False", "True"):   323             return encode_path("__builtins__.boolean.%s" % self.value)   324         elif self.value == "None":   325             return encode_path("__builtins__.none.%s" % self.value)   326         elif self.value == "NotImplemented":   327             return encode_path("__builtins__.notimplemented.%s" % self.value)   328         else:   329             return self.value   330    331     def __repr__(self):   332         return "PredefinedConstantRef(%r)" % self.value   333    334 class LogicalResult(Result):   335    336     "A logical expression result."   337    338     def _convert(self, expr):   339    340         "Return 'expr' converted to a testable value."   341    342         if isinstance(expr, LogicalResult):   343             return expr.apply_test()   344         else:   345             return "__BOOL(%s)" % expr   346    347 class NegationResult(LogicalResult):   348    349     "A negation expression result."   350    351     def __init__(self, expr):   352         self.expr = expr   353    354     def apply_test(self):   355    356         "Return the result in a form suitable for direct testing."   357    358         expr = self._convert(self.expr)   359         return "(!%s)" % expr   360    361     def discards_temporary(self, test=True):   362    363         """   364         Negations should have discarded their operand's temporary names when   365         being instantiated.   366         """   367    368         return None   369    370     def __str__(self):   371         return "(%s ? %s : %s)" % (   372             self._convert(self.expr),   373             PredefinedConstantRef("False"),   374             PredefinedConstantRef("True"))   375    376     def __repr__(self):   377         return "NegationResult(%r)" % self.expr   378    379 class LogicalOperationResult(LogicalResult):   380    381     "A logical operation result."   382    383     def __init__(self, exprs, conjunction):   384         self.exprs = exprs   385         self.conjunction = conjunction   386    387     def apply_test(self):   388    389         """   390         Return the result in a form suitable for direct testing.   391    392         Convert ... to ...   393    394         <a> and <b>   395         ((__BOOL(<a>)) && (__BOOL(<b>)))   396    397         <a> or <b>   398         ((__BOOL(<a>)) || (__BOOL(<b>)))   399         """   400    401         results = []   402         for expr in self.exprs:   403             results.append(self._convert(expr))   404    405         if self.conjunction:   406             return "(%s)" % " && ".join(results)   407         else:   408             return "(%s)" % " || ".join(results)   409    410     def discards_temporary(self, test=True):   411    412         """   413         Return a list of temporary names that can be discarded if 'test' is   414         specified as a true value (or omitted).   415         """   416    417         if not test:   418             return None   419    420         temps = ["__tmp_result"]   421    422         for expr in self.exprs:   423             t = expr.discards_temporary(test)   424             if t:   425                 temps += t   426    427         return temps   428    429     def __str__(self):   430    431         """   432         Convert ... to ...   433    434         <a> and <b>   435         (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b>   436    437         <a> or <b>   438         (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b>   439         """   440    441         results = []   442         for expr in self.exprs[:-1]:   443             results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, self.conjunction and "!" or ""))   444         results.append(str(self.exprs[-1]))   445    446         return "(%s)" % "".join(results)   447    448     def __repr__(self):   449         return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)   450    451 # vim: tabstop=4 expandtab shiftwidth=4