Lichen

transresults.py

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