Lichen

transresults.py

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