Lichen

transresults.py

756:195b15f90472
2017-03-21 Paul Boddie Allocate integers using a different allocator employing GC_MALLOC_ATOMIC.
     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 __str__(self):    75     76         "Return an output representation of the referenced name."    77     78         # Temporary names are output program locals.    79     80         if self.name.startswith("$t"):    81             if self.expr:    82                 return "%s = %s" % (encode_path(self.name), self.expr)    83             else:    84                 return encode_path(self.name)    85     86         # For sources, any identified static origin will be constant and thus    87         # usable directly. For targets, no constant should be assigned and thus    88         # the alias (or any plain name) will be used.    89     90         ref = self.static()    91         origin = ref and self.get_origin()    92         static_name = origin and encode_path(origin)    93     94         # Determine whether a qualified name is involved.    95     96         t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1)    97         parent = len(t) > 1 and t[0] or None    98         attrname = t[-1] and encode_path(t[-1])    99    100         # Assignments.   101    102         if self.expr:   103    104             # Eliminate assignments between constants.   105    106             if ref and self.expr.static():   107                 return ""   108    109             # Qualified names must be converted into parent-relative assignments.   110    111             elif parent:   112                 return "__store_via_object(&%s, %s, %s)" % (   113                     encode_path(parent), attrname, self.expr)   114    115             # All other assignments involve the names as they were given.   116    117             else:   118                 return "(%s%s) = %s" % (self.parameter and "*" or "", attrname, self.expr)   119    120         # Expressions.   121    122         elif static_name:   123             parent = ref.parent()   124             context = ref.has_kind("<function>") and encode_path(parent) or None   125             return "__ATTRVALUE(&%s)" % static_name   126    127         # Qualified names must be converted into parent-relative accesses.   128    129         elif parent:   130             return "__load_via_object(&%s, %s)" % (   131                 encode_path(parent), attrname)   132    133         # All other accesses involve the names as they were given.   134    135         else:   136             return "(%s%s)" % (self.parameter and "*" or "", attrname)   137    138 class TrConstantValueRef(ConstantValueRef):   139    140     "A constant value reference in the translation."   141    142     def __str__(self):   143         return encode_literal_constant(self.number)   144    145 class TrLiteralSequenceRef(LiteralSequenceRef):   146    147     "A reference representing a sequence of values."   148    149     def __str__(self):   150         return str(self.node)   151    152 class TrInstanceRef(InstanceRef):   153    154     "A reference representing instantiation of a class."   155    156     def __init__(self, ref, expr):   157    158         """   159         Initialise the reference with 'ref' indicating the nature of the   160         reference and 'expr' being an expression used to create the instance.   161         """   162    163         InstanceRef.__init__(self, ref)   164         self.expr = expr   165    166     def __str__(self):   167         return self.expr   168    169     def __repr__(self):   170         return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)   171    172 class AttrResult(Result, InstructionSequence):   173    174     "A translation result for an attribute access."   175    176     def __init__(self, instructions, refs, location, context_identity):   177         InstructionSequence.__init__(self, instructions)   178         self.refs = refs   179         self.location = location   180         self.context_identity = context_identity   181    182     def references(self):   183         return self.refs   184    185     def access_location(self):   186         return self.location   187    188     def context(self):   189         return self.context_identity   190    191     def get_origin(self):   192         return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()   193    194     def has_kind(self, kinds):   195         if not self.refs:   196             return False   197         for ref in self.refs:   198             if ref.has_kind(kinds):   199                 return True   200         return False   201    202     def __nonzero__(self):   203         return bool(self.instructions)   204    205     def __str__(self):   206         return encode_instructions(self.instructions)   207    208     def __repr__(self):   209         return "AttrResult(%r, %r, %r, %r)" % (self.instructions, self.refs, self.location, self.context_identity)   210    211 class AliasResult(NameRef, Result):   212    213     "An alias for other values."   214    215     def __init__(self, name_ref, refs, location):   216         NameRef.__init__(self, name_ref.name, is_global=name_ref.is_global_name())   217         self.name_ref = name_ref   218         self.refs = refs   219         self.location = location   220    221     def references(self):   222         ref = self.name_ref.reference()   223         return self.refs or ref and [ref] or None   224    225     def reference(self):   226         refs = self.references()   227         return len(refs) == 1 and first(refs) or None   228    229     def access_location(self):   230         return self.location   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