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""" Tree nodes for built-in references. 19 20There is 2 major types of built-in references. One is the values from 21built-ins, the other is built-in exceptions. They work differently and 22mean different things, but they have similar origin, that is, access 23to variables only ever read. 24 25""" 26 27 28from nuitka.Builtins import ( 29 builtin_anon_names, 30 builtin_exception_names, 31 builtin_exception_values, 32 builtin_names, 33 builtin_type_names, 34) 35from nuitka.Options import hasPythonFlagNoAsserts 36from nuitka.PythonVersions import python_version 37from nuitka.specs import BuiltinParameterSpecs 38 39from .ConstantRefNodes import makeConstantRefNode 40from .ExceptionNodes import ( 41 ExpressionBuiltinMakeException, 42 ExpressionBuiltinMakeExceptionImportError, 43) 44from .ExpressionBases import CompileTimeConstantExpressionBase 45from .shapes.BuiltinTypeShapes import tshape_exception_class 46 47 48class ExpressionBuiltinRefBase(CompileTimeConstantExpressionBase): 49 # Base classes can be abstract, pylint: disable=abstract-method 50 51 __slots__ = ("builtin_name",) 52 53 def __init__(self, builtin_name, source_ref): 54 CompileTimeConstantExpressionBase.__init__(self, source_ref=source_ref) 55 56 self.builtin_name = builtin_name 57 58 def finalize(self): 59 del self.parent 60 61 def getDetails(self): 62 return {"builtin_name": self.builtin_name} 63 64 def getBuiltinName(self): 65 return self.builtin_name 66 67 @staticmethod 68 def isKnownToBeHashable(): 69 return True 70 71 @staticmethod 72 def mayRaiseException(exception_type): 73 return False 74 75 @staticmethod 76 def mayHaveSideEffects(): 77 return False 78 79 def getStrValue(self): 80 return makeConstantRefNode( 81 constant=str(self.getCompileTimeConstant()), 82 user_provided=True, 83 source_ref=self.source_ref, 84 ) 85 86 87def makeExpressionBuiltinTypeRef(builtin_name, source_ref): 88 return makeConstantRefNode( 89 constant=__builtins__[builtin_name], source_ref=source_ref 90 ) 91 92 93quick_names = {"None": None, "True": True, "False": False, "Ellipsis": Ellipsis} 94 95 96def makeExpressionBuiltinRef(builtin_name, locals_scope, source_ref): 97 assert builtin_name in builtin_names, builtin_name 98 99 if builtin_name in quick_names: 100 return makeConstantRefNode( 101 constant=quick_names[builtin_name], source_ref=source_ref 102 ) 103 elif builtin_name == "__debug__": 104 return makeConstantRefNode( 105 constant=not hasPythonFlagNoAsserts(), source_ref=source_ref 106 ) 107 elif builtin_name in builtin_type_names: 108 return makeExpressionBuiltinTypeRef( 109 builtin_name=builtin_name, source_ref=source_ref 110 ) 111 elif builtin_name in ("dir", "eval", "exec", "execfile", "locals", "vars"): 112 return ExpressionBuiltinWithContextRef( 113 builtin_name=builtin_name, locals_scope=locals_scope, source_ref=source_ref 114 ) 115 else: 116 return ExpressionBuiltinRef(builtin_name=builtin_name, source_ref=source_ref) 117 118 119class ExpressionBuiltinRef(ExpressionBuiltinRefBase): 120 kind = "EXPRESSION_BUILTIN_REF" 121 122 __slots__ = () 123 124 # For overload 125 locals_scope = None 126 127 @staticmethod 128 def isExpressionBuiltinRef(): 129 return True 130 131 def __init__(self, builtin_name, source_ref): 132 ExpressionBuiltinRefBase.__init__( 133 self, builtin_name=builtin_name, source_ref=source_ref 134 ) 135 136 def getCompileTimeConstant(self): 137 return __builtins__[self.builtin_name] 138 139 def computeExpressionRaw(self, trace_collection): 140 return self, None, None 141 142 def computeExpressionCall(self, call_node, call_args, call_kw, trace_collection): 143 from nuitka.optimizations.OptimizeBuiltinCalls import ( 144 computeBuiltinCall, 145 ) 146 147 # Anything may happen. On next pass, if replaced, we might be better 148 # but not now. 149 trace_collection.onExceptionRaiseExit(BaseException) 150 151 new_node, tags, message = computeBuiltinCall( 152 builtin_name=self.builtin_name, call_node=call_node 153 ) 154 155 if self.builtin_name in ("dir", "eval", "exec", "execfile", "locals", "vars"): 156 # Just inform the collection that all has escaped. 157 trace_collection.onLocalsUsage(locals_scope=self.getLocalsScope()) 158 159 return new_node, tags, message 160 161 @staticmethod 162 def isKnownToBeIterable(count): 163 # TODO: Why yes, some may be, could be told here. 164 return None 165 166 167class ExpressionBuiltinWithContextRef(ExpressionBuiltinRef): 168 """Same as ExpressionBuiltinRef, but with a context it refers to.""" 169 170 kind = "EXPRESSION_BUILTIN_WITH_CONTEXT_REF" 171 172 __slots__ = ("locals_scope",) 173 174 def __init__(self, builtin_name, locals_scope, source_ref): 175 ExpressionBuiltinRef.__init__( 176 self, builtin_name=builtin_name, source_ref=source_ref 177 ) 178 179 self.locals_scope = locals_scope 180 181 def getDetails(self): 182 return {"builtin_name": self.builtin_name, "locals_scope": self.locals_scope} 183 184 def getLocalsScope(self): 185 return self.locals_scope 186 187 188class ExpressionBuiltinAnonymousRef(ExpressionBuiltinRefBase): 189 kind = "EXPRESSION_BUILTIN_ANONYMOUS_REF" 190 191 __slots__ = () 192 193 def __init__(self, builtin_name, source_ref): 194 assert builtin_name in builtin_anon_names, builtin_name 195 196 ExpressionBuiltinRefBase.__init__( 197 self, builtin_name=builtin_name, source_ref=source_ref 198 ) 199 200 def getCompileTimeConstant(self): 201 return builtin_anon_names[self.builtin_name] 202 203 def computeExpressionRaw(self, trace_collection): 204 return self, None, None 205 206 207class ExpressionBuiltinExceptionRef(ExpressionBuiltinRefBase): 208 kind = "EXPRESSION_BUILTIN_EXCEPTION_REF" 209 210 __slots__ = () 211 212 def __init__(self, exception_name, source_ref): 213 assert exception_name in builtin_exception_names, exception_name 214 215 ExpressionBuiltinRefBase.__init__( 216 self, builtin_name=exception_name, source_ref=source_ref 217 ) 218 219 def getDetails(self): 220 return {"exception_name": self.builtin_name} 221 222 getExceptionName = ExpressionBuiltinRefBase.getBuiltinName 223 224 @staticmethod 225 def getTypeShape(): 226 return tshape_exception_class 227 228 @staticmethod 229 def mayRaiseException(exception_type): 230 return False 231 232 def getCompileTimeConstant(self): 233 return builtin_exception_values[self.builtin_name] 234 235 def computeExpressionRaw(self, trace_collection): 236 # Not much that can be done here. 237 return self, None, None 238 239 def computeExpressionCall(self, call_node, call_args, call_kw, trace_collection): 240 exception_name = self.getExceptionName() 241 242 def createBuiltinMakeException(args, name=None, path=None, source_ref=None): 243 if exception_name == "ImportError" and python_version >= 0x300: 244 return ExpressionBuiltinMakeExceptionImportError( 245 exception_name=exception_name, 246 args=args, 247 name=name, 248 path=path, 249 source_ref=source_ref, 250 ) 251 else: 252 # We expect to only get the star arguments for these. 253 assert name is None 254 assert path is None 255 256 return ExpressionBuiltinMakeException( 257 exception_name=exception_name, args=args, source_ref=source_ref 258 ) 259 260 new_node = BuiltinParameterSpecs.extractBuiltinArgs( 261 node=call_node, 262 builtin_class=createBuiltinMakeException, 263 builtin_spec=BuiltinParameterSpecs.makeBuiltinExceptionParameterSpec( 264 exception_name=exception_name 265 ), 266 ) 267 268 assert new_node is not None 269 270 return new_node, "new_expression", "Detected built-in exception making." 271