Lichen

transresults.py

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