1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/transresults.py Tue Feb 28 00:00:09 2017 +0100
1.3 @@ -0,0 +1,326 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Translation result abstractions.
1.8 +
1.9 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This program is free software; you can redistribute it and/or modify it under
1.12 +the terms of the GNU General Public License as published by the Free Software
1.13 +Foundation; either version 3 of the License, or (at your option) any later
1.14 +version.
1.15 +
1.16 +This program is distributed in the hope that it will be useful, but WITHOUT
1.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 +details.
1.20 +
1.21 +You should have received a copy of the GNU General Public License along with
1.22 +this program. If not, see <http://www.gnu.org/licenses/>.
1.23 +"""
1.24 +
1.25 +from common import first, InstructionSequence
1.26 +from encoders import encode_instructions, encode_literal_constant, encode_path
1.27 +from results import ConstantValueRef, InstanceRef, LiteralSequenceRef, \
1.28 + ResolvedNameRef, Result
1.29 +
1.30 +# Classes representing intermediate translation results.
1.31 +
1.32 +class ReturnRef:
1.33 +
1.34 + "Indicates usage of a return statement."
1.35 +
1.36 + pass
1.37 +
1.38 +class Expression(Result):
1.39 +
1.40 + "A general expression."
1.41 +
1.42 + def __init__(self, s):
1.43 + self.s = s
1.44 + def __str__(self):
1.45 + return self.s
1.46 + def __repr__(self):
1.47 + return "Expression(%r)" % self.s
1.48 +
1.49 +class TrResolvedNameRef(ResolvedNameRef):
1.50 +
1.51 + "A reference to a name in the translation."
1.52 +
1.53 + def __init__(self, name, ref, expr=None, is_global=False, parameter=None, location=None):
1.54 + ResolvedNameRef.__init__(self, name, ref, expr, is_global)
1.55 + self.parameter = parameter
1.56 + self.location = location
1.57 +
1.58 + def access_location(self):
1.59 + return self.location
1.60 +
1.61 + def __str__(self):
1.62 +
1.63 + "Return an output representation of the referenced name."
1.64 +
1.65 + # For sources, any identified static origin will be constant and thus
1.66 + # usable directly. For targets, no constant should be assigned and thus
1.67 + # the alias (or any plain name) will be used.
1.68 +
1.69 + ref = self.static()
1.70 + origin = ref and self.get_origin()
1.71 + static_name = origin and encode_path(origin)
1.72 +
1.73 + # Determine whether a qualified name is involved.
1.74 +
1.75 + t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1)
1.76 + parent = len(t) > 1 and t[0] or None
1.77 + attrname = t[-1] and encode_path(t[-1])
1.78 +
1.79 + # Assignments.
1.80 +
1.81 + if self.expr:
1.82 +
1.83 + # Eliminate assignments between constants.
1.84 +
1.85 + if ref and isinstance(self.expr, ResolvedNameRef) and self.expr.static():
1.86 + return ""
1.87 +
1.88 + # Qualified names must be converted into parent-relative assignments.
1.89 +
1.90 + elif parent:
1.91 + return "__store_via_object(&%s, %s, %s)" % (
1.92 + encode_path(parent), attrname, self.expr)
1.93 +
1.94 + # All other assignments involve the names as they were given.
1.95 +
1.96 + else:
1.97 + return "(%s%s) = %s" % (self.parameter and "*" or "", attrname, self.expr)
1.98 +
1.99 + # Expressions.
1.100 +
1.101 + elif static_name:
1.102 + parent = ref.parent()
1.103 + context = ref.has_kind("<function>") and encode_path(parent) or None
1.104 + return "__ATTRVALUE(&%s)" % static_name
1.105 +
1.106 + # Qualified names must be converted into parent-relative accesses.
1.107 +
1.108 + elif parent:
1.109 + return "__load_via_object(&%s, %s)" % (
1.110 + encode_path(parent), attrname)
1.111 +
1.112 + # All other accesses involve the names as they were given.
1.113 +
1.114 + else:
1.115 + return "(%s%s)" % (self.parameter and "*" or "", attrname)
1.116 +
1.117 +class TrConstantValueRef(ConstantValueRef):
1.118 +
1.119 + "A constant value reference in the translation."
1.120 +
1.121 + def __str__(self):
1.122 + return encode_literal_constant(self.number)
1.123 +
1.124 +class TrLiteralSequenceRef(LiteralSequenceRef):
1.125 +
1.126 + "A reference representing a sequence of values."
1.127 +
1.128 + def __str__(self):
1.129 + return str(self.node)
1.130 +
1.131 +class TrInstanceRef(InstanceRef):
1.132 +
1.133 + "A reference representing instantiation of a class."
1.134 +
1.135 + def __init__(self, ref, expr):
1.136 +
1.137 + """
1.138 + Initialise the reference with 'ref' indicating the nature of the
1.139 + reference and 'expr' being an expression used to create the instance.
1.140 + """
1.141 +
1.142 + InstanceRef.__init__(self, ref)
1.143 + self.expr = expr
1.144 +
1.145 + def __str__(self):
1.146 + return self.expr
1.147 +
1.148 + def __repr__(self):
1.149 + return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr)
1.150 +
1.151 +class AttrResult(Result, InstructionSequence):
1.152 +
1.153 + "A translation result for an attribute access."
1.154 +
1.155 + def __init__(self, instructions, refs, location, context_identity):
1.156 + InstructionSequence.__init__(self, instructions)
1.157 + self.refs = refs
1.158 + self.location = location
1.159 + self.context_identity = context_identity
1.160 +
1.161 + def references(self):
1.162 + return self.refs
1.163 +
1.164 + def access_location(self):
1.165 + return self.location
1.166 +
1.167 + def context(self):
1.168 + return self.context_identity
1.169 +
1.170 + def get_origin(self):
1.171 + return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()
1.172 +
1.173 + def has_kind(self, kinds):
1.174 + if not self.refs:
1.175 + return False
1.176 + for ref in self.refs:
1.177 + if ref.has_kind(kinds):
1.178 + return True
1.179 + return False
1.180 +
1.181 + def __nonzero__(self):
1.182 + return bool(self.instructions)
1.183 +
1.184 + def __str__(self):
1.185 + return encode_instructions(self.instructions)
1.186 +
1.187 + def __repr__(self):
1.188 + return "AttrResult(%r, %r, %r)" % (self.instructions, self.refs, self.location)
1.189 +
1.190 +class InvocationResult(Result, InstructionSequence):
1.191 +
1.192 + "A translation result for an invocation."
1.193 +
1.194 + def __str__(self):
1.195 + return encode_instructions(self.instructions)
1.196 +
1.197 + def __repr__(self):
1.198 + return "InvocationResult(%r)" % self.instructions
1.199 +
1.200 +class InstantiationResult(InvocationResult, TrInstanceRef):
1.201 +
1.202 + "An instantiation result acting like an invocation result."
1.203 +
1.204 + def __init__(self, ref, instructions):
1.205 + InstanceRef.__init__(self, ref)
1.206 + InvocationResult.__init__(self, instructions)
1.207 +
1.208 + def __repr__(self):
1.209 + return "InstantiationResult(%r, %r)" % (self.ref, self.instructions)
1.210 +
1.211 +class PredefinedConstantRef(Result):
1.212 +
1.213 + "A predefined constant reference."
1.214 +
1.215 + def __init__(self, value, expr=None):
1.216 + self.value = value
1.217 + self.expr = expr
1.218 +
1.219 + def __str__(self):
1.220 +
1.221 + # Eliminate predefined constant assignments.
1.222 +
1.223 + if self.expr:
1.224 + return ""
1.225 +
1.226 + # Generate the specific constants.
1.227 +
1.228 + if self.value in ("False", "True"):
1.229 + return encode_path("__builtins__.boolean.%s" % self.value)
1.230 + elif self.value == "None":
1.231 + return encode_path("__builtins__.none.%s" % self.value)
1.232 + elif self.value == "NotImplemented":
1.233 + return encode_path("__builtins__.notimplemented.%s" % self.value)
1.234 + else:
1.235 + return self.value
1.236 +
1.237 + def __repr__(self):
1.238 + return "PredefinedConstantRef(%r)" % self.value
1.239 +
1.240 +class LogicalResult(Result):
1.241 +
1.242 + "A logical expression result."
1.243 +
1.244 + def _convert(self, expr):
1.245 +
1.246 + "Return 'expr' converted to a testable value."
1.247 +
1.248 + if isinstance(expr, LogicalResult):
1.249 + return expr.apply_test()
1.250 + else:
1.251 + return "__BOOL(%s)" % expr
1.252 +
1.253 +class NegationResult(LogicalResult):
1.254 +
1.255 + "A negation expression result."
1.256 +
1.257 + def __init__(self, expr):
1.258 + self.expr = expr
1.259 +
1.260 + def apply_test(self):
1.261 +
1.262 + "Return the result in a form suitable for direct testing."
1.263 +
1.264 + expr = self._convert(self.expr)
1.265 + return "(!%s)" % expr
1.266 +
1.267 + def __str__(self):
1.268 + return "(%s ? %s : %s)" % (
1.269 + self._convert(self.expr),
1.270 + PredefinedConstantRef("False"),
1.271 + PredefinedConstantRef("True"))
1.272 +
1.273 + def __repr__(self):
1.274 + return "NegationResult(%r)" % self.expr
1.275 +
1.276 +class LogicalOperationResult(LogicalResult):
1.277 +
1.278 + "A logical operation result."
1.279 +
1.280 + def __init__(self, exprs, conjunction):
1.281 + self.exprs = exprs
1.282 + self.conjunction = conjunction
1.283 +
1.284 + def apply_test(self):
1.285 +
1.286 + """
1.287 + Return the result in a form suitable for direct testing.
1.288 +
1.289 + Convert ... to ...
1.290 +
1.291 + <a> and <b>
1.292 + ((__BOOL(<a>)) && (__BOOL(<b>)))
1.293 +
1.294 + <a> or <b>
1.295 + ((__BOOL(<a>)) || (__BOOL(<b>)))
1.296 + """
1.297 +
1.298 + results = []
1.299 + for expr in self.exprs:
1.300 + results.append(self._convert(expr))
1.301 +
1.302 + if self.conjunction:
1.303 + return "(%s)" % " && ".join(results)
1.304 + else:
1.305 + return "(%s)" % " || ".join(results)
1.306 +
1.307 + def __str__(self):
1.308 +
1.309 + """
1.310 + Convert ... to ...
1.311 +
1.312 + <a> and <b>
1.313 + (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b>
1.314 +
1.315 + <a> or <b>
1.316 + (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b>
1.317 + """
1.318 +
1.319 + results = []
1.320 + for expr in self.exprs[:-1]:
1.321 + results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, self.conjunction and "!" or ""))
1.322 + results.append(str(self.exprs[-1]))
1.323 +
1.324 + return "(%s)" % "".join(results)
1.325 +
1.326 + def __repr__(self):
1.327 + return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction)
1.328 +
1.329 +# vim: tabstop=4 expandtab shiftwidth=4