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 self.s = s 41 def __str__(self): 42 return self.s 43 def __repr__(self): 44 return "Expression(%r)" % self.s 45 46 class TrResolvedNameRef(ResolvedNameRef): 47 48 "A reference to a name in the translation." 49 50 def __init__(self, name, ref, expr=None, is_global=False, parameter=None, location=None): 51 ResolvedNameRef.__init__(self, name, ref, expr, is_global) 52 self.parameter = parameter 53 self.location = location 54 55 def access_location(self): 56 return self.location 57 58 def __str__(self): 59 60 "Return an output representation of the referenced name." 61 62 # For sources, any identified static origin will be constant and thus 63 # usable directly. For targets, no constant should be assigned and thus 64 # the alias (or any plain name) will be used. 65 66 ref = self.static() 67 origin = ref and self.get_origin() 68 static_name = origin and encode_path(origin) 69 70 # Determine whether a qualified name is involved. 71 72 t = (not self.is_constant_alias() and self.get_name() or self.name).rsplit(".", 1) 73 parent = len(t) > 1 and t[0] or None 74 attrname = t[-1] and encode_path(t[-1]) 75 76 # Assignments. 77 78 if self.expr: 79 80 # Eliminate assignments between constants. 81 82 if ref and isinstance(self.expr, ResolvedNameRef) and self.expr.static(): 83 return "" 84 85 # Qualified names must be converted into parent-relative assignments. 86 87 elif parent: 88 return "__store_via_object(&%s, %s, %s)" % ( 89 encode_path(parent), attrname, self.expr) 90 91 # All other assignments involve the names as they were given. 92 93 else: 94 return "(%s%s) = %s" % (self.parameter and "*" or "", attrname, self.expr) 95 96 # Expressions. 97 98 elif static_name: 99 parent = ref.parent() 100 context = ref.has_kind("<function>") and encode_path(parent) or None 101 return "__ATTRVALUE(&%s)" % static_name 102 103 # Qualified names must be converted into parent-relative accesses. 104 105 elif parent: 106 return "__load_via_object(&%s, %s)" % ( 107 encode_path(parent), attrname) 108 109 # All other accesses involve the names as they were given. 110 111 else: 112 return "(%s%s)" % (self.parameter and "*" or "", attrname) 113 114 class TrConstantValueRef(ConstantValueRef): 115 116 "A constant value reference in the translation." 117 118 def __str__(self): 119 return encode_literal_constant(self.number) 120 121 class TrLiteralSequenceRef(LiteralSequenceRef): 122 123 "A reference representing a sequence of values." 124 125 def __str__(self): 126 return str(self.node) 127 128 class TrInstanceRef(InstanceRef): 129 130 "A reference representing instantiation of a class." 131 132 def __init__(self, ref, expr): 133 134 """ 135 Initialise the reference with 'ref' indicating the nature of the 136 reference and 'expr' being an expression used to create the instance. 137 """ 138 139 InstanceRef.__init__(self, ref) 140 self.expr = expr 141 142 def __str__(self): 143 return self.expr 144 145 def __repr__(self): 146 return "TrResolvedInstanceRef(%r, %r)" % (self.ref, self.expr) 147 148 class AttrResult(Result, InstructionSequence): 149 150 "A translation result for an attribute access." 151 152 def __init__(self, instructions, refs, location, context_identity): 153 InstructionSequence.__init__(self, instructions) 154 self.refs = refs 155 self.location = location 156 self.context_identity = context_identity 157 158 def references(self): 159 return self.refs 160 161 def access_location(self): 162 return self.location 163 164 def context(self): 165 return self.context_identity 166 167 def get_origin(self): 168 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() 169 170 def has_kind(self, kinds): 171 if not self.refs: 172 return False 173 for ref in self.refs: 174 if ref.has_kind(kinds): 175 return True 176 return False 177 178 def __nonzero__(self): 179 return bool(self.instructions) 180 181 def __str__(self): 182 return encode_instructions(self.instructions) 183 184 def __repr__(self): 185 return "AttrResult(%r, %r, %r)" % (self.instructions, self.refs, self.location) 186 187 class InvocationResult(Result, InstructionSequence): 188 189 "A translation result for an invocation." 190 191 def __str__(self): 192 return encode_instructions(self.instructions) 193 194 def __repr__(self): 195 return "InvocationResult(%r)" % self.instructions 196 197 class InstantiationResult(InvocationResult, TrInstanceRef): 198 199 "An instantiation result acting like an invocation result." 200 201 def __init__(self, ref, instructions): 202 InstanceRef.__init__(self, ref) 203 InvocationResult.__init__(self, instructions) 204 205 def __repr__(self): 206 return "InstantiationResult(%r, %r)" % (self.ref, self.instructions) 207 208 class PredefinedConstantRef(Result): 209 210 "A predefined constant reference." 211 212 def __init__(self, value, expr=None): 213 self.value = value 214 self.expr = expr 215 216 def __str__(self): 217 218 # Eliminate predefined constant assignments. 219 220 if self.expr: 221 return "" 222 223 # Generate the specific constants. 224 225 if self.value in ("False", "True"): 226 return encode_path("__builtins__.boolean.%s" % self.value) 227 elif self.value == "None": 228 return encode_path("__builtins__.none.%s" % self.value) 229 elif self.value == "NotImplemented": 230 return encode_path("__builtins__.notimplemented.%s" % self.value) 231 else: 232 return self.value 233 234 def __repr__(self): 235 return "PredefinedConstantRef(%r)" % self.value 236 237 class LogicalResult(Result): 238 239 "A logical expression result." 240 241 def _convert(self, expr): 242 243 "Return 'expr' converted to a testable value." 244 245 if isinstance(expr, LogicalResult): 246 return expr.apply_test() 247 else: 248 return "__BOOL(%s)" % expr 249 250 class NegationResult(LogicalResult): 251 252 "A negation expression result." 253 254 def __init__(self, expr): 255 self.expr = expr 256 257 def apply_test(self): 258 259 "Return the result in a form suitable for direct testing." 260 261 expr = self._convert(self.expr) 262 return "(!%s)" % expr 263 264 def __str__(self): 265 return "(%s ? %s : %s)" % ( 266 self._convert(self.expr), 267 PredefinedConstantRef("False"), 268 PredefinedConstantRef("True")) 269 270 def __repr__(self): 271 return "NegationResult(%r)" % self.expr 272 273 class LogicalOperationResult(LogicalResult): 274 275 "A logical operation result." 276 277 def __init__(self, exprs, conjunction): 278 self.exprs = exprs 279 self.conjunction = conjunction 280 281 def apply_test(self): 282 283 """ 284 Return the result in a form suitable for direct testing. 285 286 Convert ... to ... 287 288 <a> and <b> 289 ((__BOOL(<a>)) && (__BOOL(<b>))) 290 291 <a> or <b> 292 ((__BOOL(<a>)) || (__BOOL(<b>))) 293 """ 294 295 results = [] 296 for expr in self.exprs: 297 results.append(self._convert(expr)) 298 299 if self.conjunction: 300 return "(%s)" % " && ".join(results) 301 else: 302 return "(%s)" % " || ".join(results) 303 304 def __str__(self): 305 306 """ 307 Convert ... to ... 308 309 <a> and <b> 310 (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b> 311 312 <a> or <b> 313 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b> 314 """ 315 316 results = [] 317 for expr in self.exprs[:-1]: 318 results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, self.conjunction and "!" or "")) 319 results.append(str(self.exprs[-1])) 320 321 return "(%s)" % "".join(results) 322 323 def __repr__(self): 324 return "LogicalOperationResult(%r, %r)" % (self.exprs, self.conjunction) 325 326 # vim: tabstop=4 expandtab shiftwidth=4