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""" Reformulation of "exec" statements 19 20Consult the developer manual for information. TODO: Add ability to sync 21source code comments with developer manual sections. 22 23""" 24 25from nuitka.nodes.AssignNodes import ( 26 StatementAssignmentVariable, 27 StatementReleaseVariable, 28) 29from nuitka.nodes.BuiltinRefNodes import ExpressionBuiltinExceptionRef 30from nuitka.nodes.ComparisonNodes import ExpressionComparisonIs 31from nuitka.nodes.ConditionalNodes import ( 32 ExpressionConditional, 33 makeStatementConditional, 34) 35from nuitka.nodes.ConstantRefNodes import ( 36 ExpressionConstantNoneRef, 37 makeConstantRefNode, 38) 39from nuitka.nodes.ExceptionNodes import StatementRaiseException 40from nuitka.nodes.ExecEvalNodes import StatementExec, StatementLocalsDictSync 41from nuitka.nodes.GlobalsLocalsNodes import ExpressionBuiltinGlobals 42from nuitka.nodes.NodeMakingHelpers import makeExpressionBuiltinLocals 43from nuitka.nodes.VariableRefNodes import ExpressionTempVariableRef 44 45from .ReformulationTryFinallyStatements import makeTryFinallyStatement 46from .TreeHelpers import ( 47 buildNode, 48 getKind, 49 makeStatementsSequence, 50 makeStatementsSequenceFromStatement, 51 makeStatementsSequenceFromStatements, 52) 53 54 55def wrapEvalGlobalsAndLocals( 56 provider, globals_node, locals_node, temp_scope, source_ref 57): 58 """Wrap the locals and globals arguments for "eval". 59 60 This is called from the outside, and when the node tree 61 already exists. 62 """ 63 64 locals_scope = provider.getLocalsScope() 65 66 globals_keeper_variable = provider.allocateTempVariable( 67 temp_scope=temp_scope, name="globals" 68 ) 69 70 locals_keeper_variable = provider.allocateTempVariable( 71 temp_scope=temp_scope, name="locals" 72 ) 73 74 if locals_node is None: 75 locals_node = ExpressionConstantNoneRef(source_ref=source_ref) 76 77 if globals_node is None: 78 globals_node = ExpressionConstantNoneRef(source_ref=source_ref) 79 80 post_statements = [] 81 82 if provider.isExpressionClassBody(): 83 post_statements.append( 84 StatementLocalsDictSync( 85 locals_scope=locals_scope, 86 locals_arg=ExpressionTempVariableRef( 87 variable=locals_keeper_variable, source_ref=source_ref 88 ), 89 source_ref=source_ref.atInternal(), 90 ) 91 ) 92 93 post_statements += ( 94 StatementReleaseVariable( 95 variable=globals_keeper_variable, source_ref=source_ref 96 ), 97 StatementReleaseVariable( 98 variable=locals_keeper_variable, source_ref=source_ref 99 ), 100 ) 101 102 # The locals default is dependent on exec_mode, globals or locals. 103 locals_default = ExpressionConditional( 104 condition=ExpressionComparisonIs( 105 left=ExpressionTempVariableRef( 106 variable=globals_keeper_variable, source_ref=source_ref 107 ), 108 right=ExpressionConstantNoneRef(source_ref=source_ref), 109 source_ref=source_ref, 110 ), 111 expression_no=ExpressionTempVariableRef( 112 variable=globals_keeper_variable, source_ref=source_ref 113 ), 114 expression_yes=makeExpressionBuiltinLocals( 115 locals_scope=locals_scope, source_ref=source_ref 116 ), 117 source_ref=source_ref, 118 ) 119 120 pre_statements = [ 121 # First assign globals and locals temporary the values given. 122 StatementAssignmentVariable( 123 variable=globals_keeper_variable, source=globals_node, source_ref=source_ref 124 ), 125 StatementAssignmentVariable( 126 variable=locals_keeper_variable, source=locals_node, source_ref=source_ref 127 ), 128 makeStatementConditional( 129 condition=ExpressionComparisonIs( 130 left=ExpressionTempVariableRef( 131 variable=locals_keeper_variable, source_ref=source_ref 132 ), 133 right=ExpressionConstantNoneRef(source_ref=source_ref), 134 source_ref=source_ref, 135 ), 136 yes_branch=StatementAssignmentVariable( 137 variable=locals_keeper_variable, 138 source=locals_default, 139 source_ref=source_ref, 140 ), 141 no_branch=None, 142 source_ref=source_ref, 143 ), 144 makeStatementConditional( 145 condition=ExpressionComparisonIs( 146 left=ExpressionTempVariableRef( 147 variable=globals_keeper_variable, source_ref=source_ref 148 ), 149 right=ExpressionConstantNoneRef(source_ref=source_ref), 150 source_ref=source_ref, 151 ), 152 yes_branch=StatementAssignmentVariable( 153 variable=globals_keeper_variable, 154 source=ExpressionBuiltinGlobals(source_ref=source_ref), 155 source_ref=source_ref, 156 ), 157 no_branch=None, 158 source_ref=source_ref, 159 ), 160 ] 161 162 return ( 163 ExpressionTempVariableRef( 164 variable=globals_keeper_variable, 165 source_ref=source_ref 166 if globals_node is None 167 else globals_node.getSourceReference(), 168 ), 169 ExpressionTempVariableRef( 170 variable=locals_keeper_variable, 171 source_ref=source_ref 172 if locals_node is None 173 else locals_node.getSourceReference(), 174 ), 175 makeStatementsSequence(pre_statements, False, source_ref), 176 makeStatementsSequence(post_statements, False, source_ref), 177 ) 178 179 180def buildExecNode(provider, node, source_ref): 181 # "exec" statements, should only occur with Python2. 182 183 # This is using many variables, due to the many details this is 184 # dealing with. The locals and globals need to be dealt with in 185 # temporary variables, and we need handling of indicators, so 186 # that is just the complexity, pylint: disable=too-many-locals 187 188 exec_globals = node.globals 189 exec_locals = node.locals 190 body = node.body 191 192 # Handle exec(a,b,c) to be same as exec a, b, c 193 if exec_locals is None and exec_globals is None and getKind(body) == "Tuple": 194 parts = body.elts 195 body = parts[0] 196 197 if len(parts) > 1: 198 exec_globals = parts[1] 199 200 if len(parts) > 2: 201 exec_locals = parts[2] 202 else: 203 return StatementRaiseException( 204 exception_type=ExpressionBuiltinExceptionRef( 205 exception_name="TypeError", source_ref=source_ref 206 ), 207 exception_value=makeConstantRefNode( 208 constant="""\ 209exec: arg 1 must be a string, file, or code object""", 210 source_ref=source_ref, 211 ), 212 exception_trace=None, 213 exception_cause=None, 214 source_ref=source_ref, 215 ) 216 217 temp_scope = provider.allocateTempScope("exec") 218 219 locals_value = buildNode(provider, exec_locals, source_ref, True) 220 221 if locals_value is None: 222 locals_value = ExpressionConstantNoneRef(source_ref=source_ref) 223 224 globals_value = buildNode(provider, exec_globals, source_ref, True) 225 226 if globals_value is None: 227 globals_value = ExpressionConstantNoneRef(source_ref=source_ref) 228 229 source_code = buildNode(provider, body, source_ref) 230 231 source_variable = provider.allocateTempVariable( 232 temp_scope=temp_scope, name="exec_source" 233 ) 234 235 globals_keeper_variable = provider.allocateTempVariable( 236 temp_scope=temp_scope, name="globals" 237 ) 238 239 locals_keeper_variable = provider.allocateTempVariable( 240 temp_scope=temp_scope, name="locals" 241 ) 242 243 plain_indicator_variable = provider.allocateTempVariable( 244 temp_scope=temp_scope, name="plain" 245 ) 246 247 tried = ( 248 # First evaluate the source code expressions. 249 StatementAssignmentVariable( 250 variable=source_variable, source=source_code, source_ref=source_ref 251 ), 252 # Assign globals and locals temporary the values given, then fix it 253 # up, taking note in the "plain" temporary variable, if it was an 254 # "exec" statement with None arguments, in which case the copy back 255 # will be necessary. 256 StatementAssignmentVariable( 257 variable=globals_keeper_variable, 258 source=globals_value, 259 source_ref=source_ref, 260 ), 261 StatementAssignmentVariable( 262 variable=locals_keeper_variable, source=locals_value, source_ref=source_ref 263 ), 264 StatementAssignmentVariable( 265 variable=plain_indicator_variable, 266 source=makeConstantRefNode(constant=False, source_ref=source_ref), 267 source_ref=source_ref, 268 ), 269 makeStatementConditional( 270 condition=ExpressionComparisonIs( 271 left=ExpressionTempVariableRef( 272 variable=globals_keeper_variable, source_ref=source_ref 273 ), 274 right=ExpressionConstantNoneRef(source_ref=source_ref), 275 source_ref=source_ref, 276 ), 277 yes_branch=makeStatementsSequenceFromStatements( 278 StatementAssignmentVariable( 279 variable=globals_keeper_variable, 280 source=ExpressionBuiltinGlobals(source_ref=source_ref), 281 source_ref=source_ref, 282 ), 283 makeStatementConditional( 284 condition=ExpressionComparisonIs( 285 left=ExpressionTempVariableRef( 286 variable=locals_keeper_variable, source_ref=source_ref 287 ), 288 right=ExpressionConstantNoneRef(source_ref=source_ref), 289 source_ref=source_ref, 290 ), 291 yes_branch=makeStatementsSequenceFromStatements( 292 StatementAssignmentVariable( 293 variable=locals_keeper_variable, 294 source=makeExpressionBuiltinLocals( 295 locals_scope=provider.getLocalsScope(), 296 source_ref=source_ref, 297 ), 298 source_ref=source_ref, 299 ), 300 StatementAssignmentVariable( 301 variable=plain_indicator_variable, 302 source=makeConstantRefNode( 303 constant=True, source_ref=source_ref 304 ), 305 source_ref=source_ref, 306 ), 307 ), 308 no_branch=None, 309 source_ref=source_ref, 310 ), 311 ), 312 no_branch=makeStatementsSequenceFromStatements( 313 makeStatementConditional( 314 condition=ExpressionComparisonIs( 315 left=ExpressionTempVariableRef( 316 variable=locals_keeper_variable, source_ref=source_ref 317 ), 318 right=ExpressionConstantNoneRef(source_ref=source_ref), 319 source_ref=source_ref, 320 ), 321 yes_branch=makeStatementsSequenceFromStatement( 322 statement=StatementAssignmentVariable( 323 variable=locals_keeper_variable, 324 source=ExpressionTempVariableRef( 325 variable=globals_keeper_variable, source_ref=source_ref 326 ), 327 source_ref=source_ref, 328 ) 329 ), 330 no_branch=None, 331 source_ref=source_ref, 332 ) 333 ), 334 source_ref=source_ref, 335 ), 336 makeTryFinallyStatement( 337 provider=provider, 338 tried=StatementExec( 339 source_code=ExpressionTempVariableRef( 340 variable=source_variable, source_ref=source_ref 341 ), 342 globals_arg=ExpressionTempVariableRef( 343 variable=globals_keeper_variable, source_ref=source_ref 344 ), 345 locals_arg=ExpressionTempVariableRef( 346 variable=locals_keeper_variable, source_ref=source_ref 347 ), 348 source_ref=source_ref, 349 ), 350 final=makeStatementConditional( 351 condition=ExpressionComparisonIs( 352 left=ExpressionTempVariableRef( 353 variable=plain_indicator_variable, source_ref=source_ref 354 ), 355 right=makeConstantRefNode(constant=True, source_ref=source_ref), 356 source_ref=source_ref, 357 ), 358 yes_branch=StatementLocalsDictSync( 359 locals_scope=provider.getLocalsScope(), 360 locals_arg=ExpressionTempVariableRef( 361 variable=locals_keeper_variable, source_ref=source_ref 362 ), 363 source_ref=source_ref, 364 ), 365 no_branch=None, 366 source_ref=source_ref, 367 ), 368 source_ref=source_ref, 369 ), 370 ) 371 372 final = ( 373 StatementReleaseVariable(variable=source_variable, source_ref=source_ref), 374 StatementReleaseVariable( 375 variable=globals_keeper_variable, source_ref=source_ref 376 ), 377 StatementReleaseVariable( 378 variable=locals_keeper_variable, source_ref=source_ref 379 ), 380 StatementReleaseVariable( 381 variable=plain_indicator_variable, source_ref=source_ref 382 ), 383 ) 384 385 return makeTryFinallyStatement( 386 provider=provider, tried=tried, final=final, source_ref=source_ref 387 ) 388 389 390# This is here, to make sure it can register, pylint: disable=W0611 391import nuitka.optimizations.OptimizeBuiltinCalls # isort:skip 392