Lichen

transresults.py

769:00e902870a29
2017-03-25 Paul Boddie Merged changes from the normal-function-parameters branch, making it the default line of development from now on.
     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         InstructionSequence.__init__(self, instructions)   183         self.refs = refs   184         self.location = location   185         self.context_identity = context_identity   186    187     def references(self):   188         return self.refs   189    190     def access_location(self):   191         return self.location   192    193     def context(self):   194         return self.context_identity   195    196     def get_origin(self):   197         return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()   198    199     def has_kind(self, kinds):   200         if not self.refs:   201             return False   202         for ref in self.refs:   203             if ref.has_kind(kinds):   204                 return True   205         return False   206    207     def __nonzero__(self):   208         return bool(self.instructions)   209    210     def __str__(self):   211         return encode_instructions(self.instructions)   212    213     def __repr__(self):   214         return "AttrResult(%r, %r, %r, %r)" % (self.instructions, self.refs, self.location, self.context_identity)   215    216 class AliasResult(NameRef, Result):   217    218     "An alias for other values."   219    220     def __init__(self, name_ref, refs, location):   221         NameRef.__init__(self, name_ref.name, is_global=name_ref.is_global_name())   222         self.name_ref = name_ref   223         self.refs = refs   224         self.location = location   225    226     def references(self):   227         ref = self.name_ref.reference()   228         return self.refs or ref and [ref] or None   229    230     def reference(self):   231         refs = self.references()   232         return len(refs) == 1 and first(refs) or None   233    234     def access_location(self):   235         return self.location   236    237     def get_name(self):   238         ref = self.reference()   239         return ref and ref.get_name()   240    241     def get_origin(self):   242         ref = self.reference()   243         return ref and ref.get_origin()   244    245     def static(self):   246         ref = self.reference()   247         return ref and ref.static()   248    249     def final(self):   250         ref = self.reference()   251         return ref and ref.final()   252    253     def has_kind(self, kinds):   254         if not self.refs:   255             return self.name_ref.has_kind(kinds)   256    257         for ref in self.refs:   258             if ref.has_kind(kinds):   259                 return True   260    261         return False   262    263     def __str__(self):   264         return str(self.name_ref)   265    266     def __repr__(self):   267         return "AliasResult(%r, %r)" % (self.name_ref, self.refs)   268    269 class InvocationResult(Result, InstructionSequence):   270    271     "A translation result for an invocation."   272    273     def __str__(self):   274         return encode_instructions(self.instructions)   275    276     def __repr__(self):   277         return "InvocationResult(%r)" % self.instructions   278    279 class InstantiationResult(InvocationResult, TrInstanceRef):   280    281     "An instantiation result acting like an invocation result."   282    283     def __init__(self, ref, instructions):   284         InstanceRef.__init__(self, ref)   285         InvocationResult.__init__(self, instructions)   286    287     def __repr__(self):   288         return "InstantiationResult(%r, %r)" % (self.ref, self.instructions)   289    290 class PredefinedConstantRef(Result):   291    292     "A predefined constant reference."   293    294     def __init__(self, value, expr=None):   295         self.value = value   296         self.expr = expr   297    298     def __str__(self):   299    300         # Eliminate predefined constant assignments.   301    302         if self.expr:   303             return ""   304    305         # Generate the specific constants.   306    307         if self.value in ("False", "True"):   308             return encode_path("__builtins__.boolean.%s" % self.value)   309         elif self.value == "None":   310             return encode_path("__builtins__.none.%s" % self.value)   311         elif self.value == "NotImplemented":   312             return encode_path("__builtins__.notimplemented.%s" % self.value)   313         else:   314             return self.value   315    316     def __repr__(self):   317         return "PredefinedConstantRef(%r)" % self.value   318    319 class LogicalResult(Result):   320    321     "A logical expression result."   322    323     def _convert(self, expr):   324    325         "Return 'expr' converted to a testable value."   326    327         if isinstance(expr, LogicalResult):   328             return expr.apply_test()   329         else:   330             return "__BOOL(%s)" % expr   331    332 class NegationResult(LogicalResult):   333    334     "A negation expression result."   335    336     def __init__(self, expr):   337         self.expr = expr   338    339     def apply_test(self):   340    341         "Return the result in a form suitable for direct testing."   342    343         expr = self._convert(self.expr)   344         return "(!%s)" % expr   345    346     def discards_temporary(self, test=True):   347    348         """   349         Negations should have discarded their operand's temporary names when   350         being instantiated.   351         """   352    353         return None   354    355     def __str__(self):   356         return "(%s ? %s : %s)" % (   357             self._convert(self.expr),   358             PredefinedConstantRef("False"),   359             PredefinedConstantRef("True"))   360    361     def __repr__(self):   362         return "NegationResult(%r)" % self.expr   363    364 class LogicalOperationResult(LogicalResult):   365    366     "A logical operation result."   367    368     def __init__(self, exprs, conjunction):   369         self.exprs = exprs   370         self.conjunction = conjunction   371    372     def apply_test(self):   373    374         """   375         Return the result in a form suitable for direct testing.   376    377         Convert ... to ...   378    379         <a> and <b>   380         ((__BOOL(<a>)) && (__BOOL(<b>)))   381    382         <a> or <b>   383         ((__BOOL(<a>)) || (__BOOL(<b>)))   384         """   385    386         results = []   387         for expr in self.exprs:   388             results.append(self._convert(expr))   389    390         if self.conjunction:   391             return "(%s)" % " && ".join(results)   392         else:   393             return "(%s)" % " || ".join(results)   394    395     def discards_temporary(self, test=True):   396    397         """   398         Return a list of temporary names that can be discarded if 'test' is   399         specified as a true value (or omitted).   400         """   401    402         if not test:   403             return None   404    405         temps = ["__tmp_result"]   406    407         for expr in self.exprs:   408             t = expr.discards_temporary(test)   409             if t:   410                 temps += t   411    412         return temps   413    414     def __str__(self):   415    416         """   417         Convert ... to ...   418    419         <a> and <b>   420         (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b>   421    422         <a> or <b>   423         (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b>   424         """   425    426         results = []   427         for expr in self.exprs[:-1]:   428             results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, self.conjunction and "!" or ""))   429         results.append(str(self.exprs[-1]))   430    431         return "(%s)" % "".join(results)   432    433     def __repr__(self):   434         return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)   435    436 # vim: tabstop=4 expandtab shiftwidth=4