Lichen

transresults.py

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