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 sequence creations. 19 20Sequences might be directly translated to constants, or they might become 21nodes that build tuples, lists, or sets. 22 23For Python3.5, unpacking can happen while creating sequences, these are 24being re-formulated to an internal function. 25 26Consult the developer manual for information. TODO: Add ability to sync 27source code comments with developer manual sections. 28 29""" 30 31from nuitka.nodes.AssignNodes import ( 32 StatementAssignmentVariable, 33 StatementReleaseVariable, 34) 35from nuitka.nodes.BuiltinIteratorNodes import ExpressionBuiltinIter1 36from nuitka.nodes.BuiltinNextNodes import ExpressionBuiltinNext1 37from nuitka.nodes.BuiltinTypeNodes import ExpressionBuiltinTuple 38from nuitka.nodes.ConstantRefNodes import makeConstantRefNode 39from nuitka.nodes.ContainerMakingNodes import ( 40 makeExpressionMakeListOrConstant, 41 makeExpressionMakeSetLiteralOrConstant, 42 makeExpressionMakeTuple, 43 makeExpressionMakeTupleOrConstant, 44) 45from nuitka.nodes.ContainerOperationNodes import ( 46 ExpressionListOperationExtend, 47 ExpressionListOperationExtendForUnpack, 48 ExpressionSetOperationUpdate, 49) 50from nuitka.nodes.FunctionNodes import ( 51 ExpressionFunctionCall, 52 ExpressionFunctionCreation, 53 ExpressionFunctionRef, 54) 55from nuitka.nodes.LoopNodes import StatementLoop, StatementLoopBreak 56from nuitka.nodes.ReturnNodes import StatementReturn 57from nuitka.nodes.StatementNodes import StatementExpressionOnly 58from nuitka.nodes.VariableRefNodes import ( 59 ExpressionTempVariableRef, 60 ExpressionVariableRef, 61) 62from nuitka.PythonVersions import python_version 63from nuitka.specs.ParameterSpecs import ParameterSpec 64 65from . import SyntaxErrors 66from .InternalModule import ( 67 internal_source_ref, 68 makeInternalHelperFunctionBody, 69 once_decorator, 70) 71from .ReformulationTryExceptStatements import makeTryExceptSingleHandlerNode 72from .ReformulationTryFinallyStatements import makeTryFinallyStatement 73from .TreeHelpers import ( 74 buildNode, 75 buildNodeList, 76 getKind, 77 makeStatementsSequenceFromStatement, 78 makeStatementsSequenceFromStatements, 79) 80 81 82def _raiseStarredSyntaxError(element, source_ref): 83 SyntaxErrors.raiseSyntaxError( 84 "can use starred expression only as assignment target", 85 source_ref.atColumnNumber(element.col_offset), 86 ) 87 88 89def buildTupleCreationNode(provider, node, source_ref): 90 if python_version >= 0x300: 91 for element in node.elts: 92 if getKind(element) == "Starred": 93 if python_version < 0x350: 94 _raiseStarredSyntaxError(element, source_ref) 95 else: 96 return buildTupleUnpacking( 97 provider=provider, elements=node.elts, source_ref=source_ref 98 ) 99 100 return makeExpressionMakeTupleOrConstant( 101 elements=buildNodeList(provider, node.elts, source_ref), 102 user_provided=True, 103 source_ref=source_ref, 104 ) 105 106 107def buildListCreationNode(provider, node, source_ref): 108 if python_version >= 0x300: 109 for element in node.elts: 110 if getKind(element) == "Starred": 111 if python_version < 0x350: 112 _raiseStarredSyntaxError(element, source_ref) 113 else: 114 return buildListUnpacking( 115 provider=provider, elements=node.elts, source_ref=source_ref 116 ) 117 118 return makeExpressionMakeListOrConstant( 119 elements=buildNodeList(provider, node.elts, source_ref), 120 user_provided=True, 121 source_ref=source_ref, 122 ) 123 124 125def buildSetCreationNode(provider, node, source_ref): 126 if python_version >= 0x300: 127 for element in node.elts: 128 if getKind(element) == "Starred": 129 if python_version < 0x350: 130 _raiseStarredSyntaxError(element, source_ref) 131 else: 132 return _buildSetUnpacking( 133 provider=provider, elements=node.elts, source_ref=source_ref 134 ) 135 136 return makeExpressionMakeSetLiteralOrConstant( 137 elements=buildNodeList(provider, node.elts, source_ref), 138 user_provided=True, 139 source_ref=source_ref, 140 ) 141 142 143@once_decorator 144def getListUnpackingHelper(): 145 helper_name = "_unpack_list" 146 147 result = makeInternalHelperFunctionBody( 148 name=helper_name, 149 parameters=ParameterSpec( 150 ps_name=helper_name, 151 ps_normal_args=(), 152 ps_list_star_arg="args", 153 ps_dict_star_arg=None, 154 ps_default_count=0, 155 ps_kw_only_args=(), 156 ps_pos_only_args=(), 157 ), 158 ) 159 160 temp_scope = None 161 162 tmp_result_variable = result.allocateTempVariable(temp_scope, "list") 163 tmp_iter_variable = result.allocateTempVariable(temp_scope, "iter") 164 tmp_item_variable = result.allocateTempVariable(temp_scope, "keys") 165 166 if python_version < 0x390: 167 list_operation_extend = ExpressionListOperationExtend 168 else: 169 list_operation_extend = ExpressionListOperationExtendForUnpack 170 171 loop_body = makeStatementsSequenceFromStatements( 172 makeTryExceptSingleHandlerNode( 173 tried=StatementAssignmentVariable( 174 variable=tmp_item_variable, 175 source=ExpressionBuiltinNext1( 176 value=ExpressionTempVariableRef( 177 variable=tmp_iter_variable, source_ref=internal_source_ref 178 ), 179 source_ref=internal_source_ref, 180 ), 181 source_ref=internal_source_ref, 182 ), 183 exception_name="StopIteration", 184 handler_body=StatementLoopBreak(source_ref=internal_source_ref), 185 source_ref=internal_source_ref, 186 ), 187 StatementExpressionOnly( 188 expression=list_operation_extend( 189 list_arg=ExpressionTempVariableRef( 190 variable=tmp_result_variable, source_ref=internal_source_ref 191 ), 192 value=ExpressionTempVariableRef( 193 variable=tmp_item_variable, source_ref=internal_source_ref 194 ), 195 source_ref=internal_source_ref, 196 ), 197 source_ref=internal_source_ref, 198 ), 199 ) 200 201 args_variable = result.getVariableForAssignment(variable_name="args") 202 203 final = ( 204 StatementReleaseVariable( 205 variable=tmp_result_variable, source_ref=internal_source_ref 206 ), 207 StatementReleaseVariable( 208 variable=tmp_iter_variable, source_ref=internal_source_ref 209 ), 210 StatementReleaseVariable( 211 variable=tmp_item_variable, source_ref=internal_source_ref 212 ), 213 ) 214 215 tried = makeStatementsSequenceFromStatements( 216 StatementAssignmentVariable( 217 variable=tmp_iter_variable, 218 source=ExpressionBuiltinIter1( 219 value=ExpressionVariableRef( 220 variable=args_variable, source_ref=internal_source_ref 221 ), 222 source_ref=internal_source_ref, 223 ), 224 source_ref=internal_source_ref, 225 ), 226 StatementAssignmentVariable( 227 variable=tmp_result_variable, 228 source=makeConstantRefNode(constant=[], source_ref=internal_source_ref), 229 source_ref=internal_source_ref, 230 ), 231 StatementLoop(loop_body=loop_body, source_ref=internal_source_ref), 232 StatementReturn( 233 expression=ExpressionTempVariableRef( 234 variable=tmp_result_variable, source_ref=internal_source_ref 235 ), 236 source_ref=internal_source_ref, 237 ), 238 ) 239 240 result.setChild( 241 "body", 242 makeStatementsSequenceFromStatement( 243 makeTryFinallyStatement( 244 provider=result, 245 tried=tried, 246 final=final, 247 source_ref=internal_source_ref, 248 ) 249 ), 250 ) 251 252 return result 253 254 255@once_decorator 256def getSetUnpackingHelper(): 257 helper_name = "_unpack_set" 258 259 result = makeInternalHelperFunctionBody( 260 name=helper_name, 261 parameters=ParameterSpec( 262 ps_name=helper_name, 263 ps_normal_args=(), 264 ps_list_star_arg="args", 265 ps_dict_star_arg=None, 266 ps_default_count=0, 267 ps_kw_only_args=(), 268 ps_pos_only_args=(), 269 ), 270 ) 271 272 temp_scope = None 273 274 tmp_result_variable = result.allocateTempVariable(temp_scope, "set") 275 tmp_iter_variable = result.allocateTempVariable(temp_scope, "iter") 276 tmp_item_variable = result.allocateTempVariable(temp_scope, "keys") 277 278 loop_body = makeStatementsSequenceFromStatements( 279 makeTryExceptSingleHandlerNode( 280 tried=StatementAssignmentVariable( 281 variable=tmp_item_variable, 282 source=ExpressionBuiltinNext1( 283 value=ExpressionTempVariableRef( 284 variable=tmp_iter_variable, source_ref=internal_source_ref 285 ), 286 source_ref=internal_source_ref, 287 ), 288 source_ref=internal_source_ref, 289 ), 290 exception_name="StopIteration", 291 handler_body=StatementLoopBreak(source_ref=internal_source_ref), 292 source_ref=internal_source_ref, 293 ), 294 StatementExpressionOnly( 295 expression=ExpressionSetOperationUpdate( 296 set_arg=ExpressionTempVariableRef( 297 variable=tmp_result_variable, source_ref=internal_source_ref 298 ), 299 value=ExpressionTempVariableRef( 300 variable=tmp_item_variable, source_ref=internal_source_ref 301 ), 302 source_ref=internal_source_ref, 303 ), 304 source_ref=internal_source_ref, 305 ), 306 ) 307 308 args_variable = result.getVariableForAssignment(variable_name="args") 309 310 final = ( 311 StatementReleaseVariable( 312 variable=tmp_result_variable, source_ref=internal_source_ref 313 ), 314 StatementReleaseVariable( 315 variable=tmp_iter_variable, source_ref=internal_source_ref 316 ), 317 StatementReleaseVariable( 318 variable=tmp_item_variable, source_ref=internal_source_ref 319 ), 320 ) 321 322 tried = makeStatementsSequenceFromStatements( 323 StatementAssignmentVariable( 324 variable=tmp_iter_variable, 325 source=ExpressionBuiltinIter1( 326 value=ExpressionVariableRef( 327 variable=args_variable, source_ref=internal_source_ref 328 ), 329 source_ref=internal_source_ref, 330 ), 331 source_ref=internal_source_ref, 332 ), 333 StatementAssignmentVariable( 334 variable=tmp_result_variable, 335 source=makeConstantRefNode(constant=set(), source_ref=internal_source_ref), 336 source_ref=internal_source_ref, 337 ), 338 StatementLoop(loop_body=loop_body, source_ref=internal_source_ref), 339 StatementReturn( 340 expression=ExpressionTempVariableRef( 341 variable=tmp_result_variable, source_ref=internal_source_ref 342 ), 343 source_ref=internal_source_ref, 344 ), 345 ) 346 347 result.setChild( 348 "body", 349 makeStatementsSequenceFromStatement( 350 makeTryFinallyStatement( 351 provider=result, 352 tried=tried, 353 final=final, 354 source_ref=internal_source_ref, 355 ) 356 ), 357 ) 358 359 return result 360 361 362def buildListUnpacking(provider, elements, source_ref): 363 helper_args = [] 364 365 for element in elements: 366 367 # We could be a lot cleverer about the tuples for non-starred 368 # arguments, but lets get this to work first. And then rely on 369 # future optimization to inline the list unpacking helper in a 370 # way that has the same effect. 371 if getKind(element) == "Starred": 372 helper_args.append(buildNode(provider, element.value, source_ref)) 373 else: 374 helper_args.append( 375 makeExpressionMakeTupleOrConstant( 376 elements=(buildNode(provider, element, source_ref),), 377 user_provided=True, 378 source_ref=source_ref, 379 ) 380 ) 381 382 result = ExpressionFunctionCall( 383 function=ExpressionFunctionCreation( 384 function_ref=ExpressionFunctionRef( 385 function_body=getListUnpackingHelper(), source_ref=source_ref 386 ), 387 defaults=(), 388 kw_defaults=None, 389 annotations=None, 390 source_ref=source_ref, 391 ), 392 values=(makeExpressionMakeTuple(helper_args, source_ref),), 393 source_ref=source_ref, 394 ) 395 396 result.setCompatibleSourceReference(helper_args[-1].getCompatibleSourceReference()) 397 398 return result 399 400 401def buildTupleUnpacking(provider, elements, source_ref): 402 return ExpressionBuiltinTuple( 403 value=buildListUnpacking(provider, elements, source_ref), source_ref=source_ref 404 ) 405 406 407def _buildSetUnpacking(provider, elements, source_ref): 408 helper_args = [] 409 410 for element in elements: 411 412 # We could be a lot cleverer about the tuples for non-starred 413 # arguments, but lets get this to work first. And then rely on 414 # future optimization to inline the list unpacking helper in a 415 # way that has the same effect. 416 if getKind(element) == "Starred": 417 helper_args.append(buildNode(provider, element.value, source_ref)) 418 else: 419 helper_args.append( 420 makeExpressionMakeTupleOrConstant( 421 elements=(buildNode(provider, element, source_ref),), 422 user_provided=True, 423 source_ref=source_ref, 424 ) 425 ) 426 427 result = ExpressionFunctionCall( 428 function=ExpressionFunctionCreation( 429 function_ref=ExpressionFunctionRef( 430 function_body=getSetUnpackingHelper(), source_ref=source_ref 431 ), 432 defaults=(), 433 kw_defaults=None, 434 annotations=None, 435 source_ref=source_ref, 436 ), 437 values=(makeExpressionMakeTuple(helper_args, source_ref),), 438 source_ref=source_ref, 439 ) 440 441 result.setCompatibleSourceReference(helper_args[-1].getCompatibleSourceReference()) 442 443 return result 444