1# Copyright 2021, Kay Hayen, mailto:kay.hayen@gmail.com 2# 3# Part of "Nuitka", an optimizing Python compiler that is compatible and 4# integrates with CPython, but also works on its own. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18""" Built-in type nodes tuple/list/set/float/str/unicode etc. 19 20These are all very simple and have predictable properties, because we know their type and 21that should allow some important optimizations. 22""" 23 24from nuitka.specs import BuiltinParameterSpecs 25 26from .ConstantRefNodes import makeConstantRefNode 27from .ExpressionBases import ( 28 CompileTimeConstantExpressionBase, 29 ExpressionBuiltinSingleArgBase, 30 ExpressionChildHavingBase, 31 ExpressionChildrenHavingBase, 32 ExpressionSpecBasedComputationMixin, 33) 34from .NodeMakingHelpers import ( 35 makeConstantReplacementNode, 36 wrapExpressionWithNodeSideEffects, 37) 38from .shapes.BuiltinTypeShapes import ( 39 tshape_bool, 40 tshape_bytearray, 41 tshape_bytes, 42 tshape_bytes_derived, 43 tshape_float_derived, 44 tshape_frozenset, 45 tshape_list, 46 tshape_set, 47 tshape_str_derived, 48 tshape_tuple, 49 tshape_unicode_derived, 50) 51 52 53class ExpressionBuiltinTypeBase(ExpressionBuiltinSingleArgBase): 54 pass 55 56 57class ExpressionBuiltinContainerBase( 58 ExpressionSpecBasedComputationMixin, ExpressionChildHavingBase 59): 60 61 builtin_spec = None 62 63 named_child = "value" 64 65 def __init__(self, value, source_ref): 66 ExpressionChildHavingBase.__init__(self, value=value, source_ref=source_ref) 67 68 def computeExpression(self, trace_collection): 69 value = self.subnode_value 70 71 if value is None: 72 return self.computeBuiltinSpec( 73 trace_collection=trace_collection, given_values=() 74 ) 75 elif value.isExpressionConstantXrangeRef(): 76 if value.getIterationLength() <= 256: 77 return self.computeBuiltinSpec( 78 trace_collection=trace_collection, given_values=(value,) 79 ) 80 else: 81 return self, None, None 82 else: 83 return self.computeBuiltinSpec( 84 trace_collection=trace_collection, given_values=(value,) 85 ) 86 87 88class ExpressionBuiltinTuple(ExpressionBuiltinContainerBase): 89 kind = "EXPRESSION_BUILTIN_TUPLE" 90 91 builtin_spec = BuiltinParameterSpecs.builtin_tuple_spec 92 93 @staticmethod 94 def getTypeShape(): 95 return tshape_tuple 96 97 98class ExpressionBuiltinList(ExpressionBuiltinContainerBase): 99 kind = "EXPRESSION_BUILTIN_LIST" 100 101 builtin_spec = BuiltinParameterSpecs.builtin_list_spec 102 103 @staticmethod 104 def getTypeShape(): 105 return tshape_list 106 107 108class ExpressionBuiltinSet(ExpressionBuiltinContainerBase): 109 kind = "EXPRESSION_BUILTIN_SET" 110 111 builtin_spec = BuiltinParameterSpecs.builtin_set_spec 112 113 @staticmethod 114 def getTypeShape(): 115 return tshape_set 116 117 118class ExpressionBuiltinFrozenset(ExpressionBuiltinContainerBase): 119 kind = "EXPRESSION_BUILTIN_FROZENSET" 120 121 builtin_spec = BuiltinParameterSpecs.builtin_frozenset_spec 122 123 @staticmethod 124 def getTypeShape(): 125 return tshape_frozenset 126 127 128class ExpressionBuiltinFloat(ExpressionChildHavingBase): 129 kind = "EXPRESSION_BUILTIN_FLOAT" 130 131 named_child = "value" 132 133 def __init__(self, value, source_ref): 134 ExpressionChildHavingBase.__init__(self, value=value, source_ref=source_ref) 135 136 @staticmethod 137 def getTypeShape(): 138 # TODO: Depending on input type shape, we should improve this. 139 return tshape_float_derived 140 141 def computeExpression(self, trace_collection): 142 return self.subnode_value.computeExpressionFloat( 143 float_node=self, trace_collection=trace_collection 144 ) 145 146 def mayRaiseException(self, exception_type): 147 return self.subnode_value.mayRaiseExceptionFloat(exception_type) 148 149 150class ExpressionBuiltinBool(ExpressionBuiltinTypeBase): 151 kind = "EXPRESSION_BUILTIN_BOOL" 152 153 builtin_spec = BuiltinParameterSpecs.builtin_bool_spec 154 155 def computeExpression(self, trace_collection): 156 value = self.subnode_value 157 158 truth_value = value.getTruthValue() 159 160 if truth_value is not None: 161 result = wrapExpressionWithNodeSideEffects( 162 new_node=makeConstantReplacementNode( 163 constant=truth_value, node=self, user_provided=False 164 ), 165 old_node=value, 166 ) 167 168 return ( 169 result, 170 "new_constant", 171 "Predicted truth value of built-in bool argument", 172 ) 173 174 return ExpressionBuiltinTypeBase.computeExpression(self, trace_collection) 175 176 @staticmethod 177 def getTypeShape(): 178 # Note: Not allowed to subclass bool. 179 return tshape_bool 180 181 182class ExpressionBuiltinUnicodeBase( 183 ExpressionSpecBasedComputationMixin, ExpressionChildrenHavingBase 184): 185 named_children = ("value", "encoding", "errors") 186 187 def __init__(self, value, encoding, errors, source_ref): 188 ExpressionChildrenHavingBase.__init__( 189 self, 190 values={"value": value, "encoding": encoding, "errors": errors}, 191 source_ref=source_ref, 192 ) 193 194 def computeExpression(self, trace_collection): 195 args = [self.subnode_value, self.subnode_encoding, self.subnode_errors] 196 197 while args and args[-1] is None: 198 del args[-1] 199 200 # The value of that node escapes and could change its contents. 201 if self.subnode_value is not None: 202 trace_collection.onValueEscapeStr(self.subnode_value) 203 204 # Any code could be run, note that. 205 trace_collection.onControlFlowEscape(self) 206 207 return self.computeBuiltinSpec( 208 trace_collection=trace_collection, given_values=tuple(args) 209 ) 210 211 212class ExpressionBuiltinStrP2(ExpressionBuiltinTypeBase): 213 """Python2 built-in str call.""" 214 215 kind = "EXPRESSION_BUILTIN_STR_P2" 216 217 builtin_spec = BuiltinParameterSpecs.builtin_str_spec 218 219 def computeExpression(self, trace_collection): 220 ( 221 new_node, 222 change_tags, 223 change_desc, 224 ) = ExpressionBuiltinTypeBase.computeExpression(self, trace_collection) 225 226 if new_node is self: 227 str_value = self.subnode_value.getStrValue() 228 229 if str_value is not None: 230 new_node = wrapExpressionWithNodeSideEffects( 231 new_node=str_value, old_node=self.subnode_value 232 ) 233 234 change_tags = "new_expression" 235 change_desc = "Predicted 'str' built-in result" 236 237 return new_node, change_tags, change_desc 238 239 @staticmethod 240 def getTypeShape(): 241 return tshape_str_derived 242 243 244class ExpressionBuiltinUnicodeP2(ExpressionBuiltinUnicodeBase): 245 """Python2 built-in unicode call.""" 246 247 kind = "EXPRESSION_BUILTIN_UNICODE_P2" 248 249 builtin_spec = BuiltinParameterSpecs.builtin_unicode_p2_spec 250 251 @staticmethod 252 def getTypeShape(): 253 return tshape_unicode_derived 254 255 256class ExpressionBuiltinStrP3(ExpressionBuiltinUnicodeBase): 257 """Python3 built-in str call.""" 258 259 kind = "EXPRESSION_BUILTIN_STR_P3" 260 261 builtin_spec = BuiltinParameterSpecs.builtin_str_spec 262 263 @staticmethod 264 def getTypeShape(): 265 return tshape_str_derived 266 267 268class ExpressionBuiltinBytes3(ExpressionBuiltinUnicodeBase): 269 kind = "EXPRESSION_BUILTIN_BYTES3" 270 271 builtin_spec = BuiltinParameterSpecs.builtin_bytes_p3_spec 272 273 @staticmethod 274 def getTypeShape(): 275 return tshape_bytes 276 277 278class ExpressionBuiltinBytes1(ExpressionChildHavingBase): 279 kind = "EXPRESSION_BUILTIN_BYTES1" 280 281 named_child = "value" 282 283 def __init__(self, value, source_ref): 284 ExpressionChildHavingBase.__init__(self, value=value, source_ref=source_ref) 285 286 @staticmethod 287 def getTypeShape(): 288 # TODO: Depending on input type shape, we should improve this. 289 return tshape_bytes_derived 290 291 def computeExpression(self, trace_collection): 292 return self.subnode_value.computeExpressionBytes( 293 bytes_node=self, trace_collection=trace_collection 294 ) 295 296 def mayRaiseException(self, exception_type): 297 return self.subnode_value.mayRaiseExceptionBytes(exception_type) 298 299 300class ExpressionBuiltinBytearray1(ExpressionBuiltinTypeBase): 301 kind = "EXPRESSION_BUILTIN_BYTEARRAY1" 302 303 builtin_spec = BuiltinParameterSpecs.builtin_bytearray_spec 304 305 def __init__(self, value, source_ref): 306 ExpressionBuiltinTypeBase.__init__(self, value=value, source_ref=source_ref) 307 308 @staticmethod 309 def getTypeShape(): 310 return tshape_bytearray 311 312 313class ExpressionBuiltinBytearray3(ExpressionChildrenHavingBase): 314 kind = "EXPRESSION_BUILTIN_BYTEARRAY3" 315 316 named_children = ("string", "encoding", "errors") 317 318 builtin_spec = BuiltinParameterSpecs.builtin_bytearray_spec 319 320 def __init__(self, string, encoding, errors, source_ref): 321 ExpressionChildrenHavingBase.__init__( 322 self, 323 values={"string": string, "encoding": encoding, "errors": errors}, 324 source_ref=source_ref, 325 ) 326 327 def computeExpression(self, trace_collection): 328 trace_collection.onExceptionRaiseExit(BaseException) 329 330 return self, None, None 331 332 @staticmethod 333 def getTypeShape(): 334 return tshape_bytearray 335 336 337class ExpressionConstantGenericAlias(CompileTimeConstantExpressionBase): 338 kind = "EXPRESSION_CONSTANT_GENERIC_ALIAS" 339 340 __slots__ = ("generic_alias",) 341 342 def __init__(self, generic_alias, source_ref): 343 CompileTimeConstantExpressionBase.__init__(self, source_ref=source_ref) 344 345 self.generic_alias = generic_alias 346 347 def finalize(self): 348 del self.parent 349 350 def getDetails(self): 351 return {"generic_alias": self.generic_alias} 352 353 @staticmethod 354 def mayRaiseException(exception_type): 355 return False 356 357 @staticmethod 358 def mayHaveSideEffects(): 359 return False 360 361 def getCompileTimeConstant(self): 362 return self.generic_alias 363 364 def getStrValue(self): 365 return makeConstantRefNode( 366 constant=str(self.getCompileTimeConstant()), 367 user_provided=True, 368 source_ref=self.source_ref, 369 ) 370 371 def computeExpressionRaw(self, trace_collection): 372 # Nothing much to do. 373 return self, None, None 374