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""" Optimize calls to built-in references to specific built-in calls.
19
20For built-in name references, we check if it's one of the supported built-in
21types, and then specialize for the ones, where it makes sense.
22"""
23
24from nuitka.__past__ import xrange  # pylint: disable=I0021,redefined-builtin
25from nuitka.Errors import NuitkaAssumptionError
26from nuitka.nodes.AssignNodes import (
27    StatementAssignmentVariable,
28    StatementDelVariable,
29)
30from nuitka.nodes.AttributeNodes import (
31    ExpressionAttributeLookup,
32    ExpressionBuiltinGetattr,
33    ExpressionBuiltinHasattr,
34    ExpressionBuiltinSetattr,
35)
36from nuitka.nodes.BuiltinAllNodes import ExpressionBuiltinAll
37from nuitka.nodes.BuiltinAnyNodes import ExpressionBuiltinAny
38from nuitka.nodes.BuiltinComplexNodes import (
39    ExpressionBuiltinComplex1,
40    ExpressionBuiltinComplex2,
41)
42from nuitka.nodes.BuiltinDecodingNodes import (
43    ExpressionBuiltinChr,
44    ExpressionBuiltinOrd,
45)
46from nuitka.nodes.BuiltinDecoratorNodes import (
47    ExpressionBuiltinClassmethod,
48    ExpressionBuiltinStaticmethod,
49)
50from nuitka.nodes.BuiltinDictNodes import ExpressionBuiltinDict
51from nuitka.nodes.BuiltinFormatNodes import (
52    ExpressionBuiltinAscii,
53    ExpressionBuiltinBin,
54    ExpressionBuiltinFormat,
55    ExpressionBuiltinHex,
56    ExpressionBuiltinId,
57    ExpressionBuiltinOct,
58)
59from nuitka.nodes.BuiltinHashNodes import ExpressionBuiltinHash
60from nuitka.nodes.BuiltinIntegerNodes import (
61    ExpressionBuiltinInt1,
62    ExpressionBuiltinInt2,
63)
64from nuitka.nodes.BuiltinIteratorNodes import (
65    ExpressionBuiltinIter1,
66    ExpressionBuiltinIter2,
67)
68from nuitka.nodes.BuiltinLenNodes import ExpressionBuiltinLen
69from nuitka.nodes.BuiltinNextNodes import (
70    ExpressionBuiltinNext1,
71    ExpressionBuiltinNext2,
72)
73from nuitka.nodes.BuiltinOpenNodes import ExpressionBuiltinOpen
74from nuitka.nodes.BuiltinRangeNodes import (
75    ExpressionBuiltinRange1,
76    ExpressionBuiltinRange2,
77    ExpressionBuiltinRange3,
78    ExpressionBuiltinXrange1,
79    ExpressionBuiltinXrange2,
80    ExpressionBuiltinXrange3,
81)
82from nuitka.nodes.BuiltinRefNodes import (
83    ExpressionBuiltinAnonymousRef,
84    makeExpressionBuiltinTypeRef,
85)
86from nuitka.nodes.BuiltinSumNodes import (
87    ExpressionBuiltinSum1,
88    ExpressionBuiltinSum2,
89)
90from nuitka.nodes.BuiltinTypeNodes import (
91    ExpressionBuiltinBool,
92    ExpressionBuiltinBytearray1,
93    ExpressionBuiltinBytearray3,
94    ExpressionBuiltinFloat,
95    ExpressionBuiltinFrozenset,
96    ExpressionBuiltinList,
97    ExpressionBuiltinSet,
98    ExpressionBuiltinStrP2,
99    ExpressionBuiltinStrP3,
100    ExpressionBuiltinTuple,
101    ExpressionBuiltinUnicodeP2,
102)
103from nuitka.nodes.BuiltinVarsNodes import ExpressionBuiltinVars
104from nuitka.nodes.CallNodes import makeExpressionCall
105from nuitka.nodes.ClassNodes import ExpressionBuiltinType3
106from nuitka.nodes.ComparisonNodes import ExpressionComparisonIs
107from nuitka.nodes.ConditionalNodes import (
108    ExpressionConditional,
109    makeStatementConditional,
110)
111from nuitka.nodes.ConstantRefNodes import makeConstantRefNode
112from nuitka.nodes.ContainerMakingNodes import makeExpressionMakeTupleOrConstant
113from nuitka.nodes.ExecEvalNodes import (
114    ExpressionBuiltinCompile,
115    ExpressionBuiltinEval,
116)
117from nuitka.nodes.GlobalsLocalsNodes import (
118    ExpressionBuiltinDir1,
119    ExpressionBuiltinGlobals,
120)
121from nuitka.nodes.ImportNodes import ExpressionBuiltinImport
122from nuitka.nodes.NodeMakingHelpers import (
123    makeConstantReplacementNode,
124    makeExpressionBuiltinLocals,
125    makeRaiseExceptionReplacementExpression,
126    makeRaiseExceptionReplacementExpressionFromInstance,
127    wrapExpressionWithSideEffects,
128)
129from nuitka.nodes.OperatorNodes import ExpressionOperationBinaryDivmod
130from nuitka.nodes.OperatorNodesUnary import (
131    ExpressionOperationNot,
132    ExpressionOperationUnaryAbs,
133    ExpressionOperationUnaryRepr,
134)
135from nuitka.nodes.OutlineNodes import ExpressionOutlineBody
136from nuitka.nodes.ReturnNodes import makeStatementReturn
137from nuitka.nodes.SliceNodes import makeExpressionBuiltinSlice
138from nuitka.nodes.TypeNodes import (
139    ExpressionBuiltinIsinstance,
140    ExpressionBuiltinIssubclass,
141    ExpressionBuiltinSuper0,
142    ExpressionBuiltinSuper2,
143    ExpressionBuiltinType1,
144)
145from nuitka.nodes.VariableRefNodes import (
146    ExpressionTempVariableRef,
147    ExpressionVariableRef,
148)
149from nuitka.PythonVersions import python_version
150from nuitka.specs import BuiltinParameterSpecs
151from nuitka.tree.ReformulationExecStatements import wrapEvalGlobalsAndLocals
152from nuitka.tree.ReformulationTryFinallyStatements import (
153    makeTryFinallyStatement,
154)
155from nuitka.tree.TreeHelpers import (
156    makeCallNode,
157    makeStatementsSequence,
158    makeStatementsSequenceFromStatement,
159)
160
161
162def dir_extractor(node):
163    locals_scope = node.subnode_called.getLocalsScope()
164
165    def buildDirEmptyCase(source_ref):
166        source = makeExpressionBuiltinLocals(
167            locals_scope=locals_scope, source_ref=source_ref
168        )
169
170        result = makeCallNode(
171            ExpressionAttributeLookup(
172                expression=source, attribute_name="keys", source_ref=source_ref
173            ),
174            source_ref,
175        )
176
177        # For Python3, keys doesn't really return values, but instead a handle
178        # only, but we want it to be a list.
179        if python_version >= 0x300:
180            result = ExpressionBuiltinList(value=result, source_ref=source_ref)
181
182        return result
183
184    return BuiltinParameterSpecs.extractBuiltinArgs(
185        node=node,
186        # TODO: Needs locals_scope attached.
187        builtin_class=ExpressionBuiltinDir1,
188        builtin_spec=BuiltinParameterSpecs.builtin_dir_spec,
189        empty_special_class=buildDirEmptyCase,
190    )
191
192
193def vars_extractor(node):
194    locals_scope = node.subnode_called.getLocalsScope()
195
196    def selectVarsEmptyClass(source_ref):
197        return makeExpressionBuiltinLocals(
198            locals_scope=locals_scope, source_ref=source_ref
199        )
200
201    return BuiltinParameterSpecs.extractBuiltinArgs(
202        node=node,
203        # TODO: Needs locals_cope attached
204        builtin_class=ExpressionBuiltinVars,
205        builtin_spec=BuiltinParameterSpecs.builtin_vars_spec,
206        empty_special_class=selectVarsEmptyClass,
207    )
208
209
210def import_extractor(node):
211    return BuiltinParameterSpecs.extractBuiltinArgs(
212        node=node,
213        builtin_class=ExpressionBuiltinImport,
214        builtin_spec=BuiltinParameterSpecs.builtin_import_spec,
215    )
216
217
218def type_extractor(node):
219    args = node.subnode_args
220
221    if args is None:
222        iter_length = 0
223    else:
224        iter_length = args.getIterationLength()
225
226    if iter_length == 1:
227        return BuiltinParameterSpecs.extractBuiltinArgs(
228            node=node,
229            builtin_class=ExpressionBuiltinType1,
230            builtin_spec=BuiltinParameterSpecs.builtin_type1_spec,
231        )
232    elif iter_length == 3:
233        return BuiltinParameterSpecs.extractBuiltinArgs(
234            node=node,
235            builtin_class=ExpressionBuiltinType3,
236            builtin_spec=BuiltinParameterSpecs.builtin_type3_spec,
237        )
238    else:
239        return makeRaiseExceptionReplacementExpressionFromInstance(
240            expression=node, exception=TypeError("type() takes 1 or 3 arguments")
241        )
242
243
244def iter_extractor(node):
245    def wrapIterCreation(callable_arg, sentinel, source_ref):
246        if sentinel is None:
247            return ExpressionBuiltinIter1(value=callable_arg, source_ref=source_ref)
248        else:
249            return ExpressionBuiltinIter2(
250                callable_arg=callable_arg, sentinel=sentinel, source_ref=source_ref
251            )
252
253    return BuiltinParameterSpecs.extractBuiltinArgs(
254        node=node,
255        builtin_class=wrapIterCreation,
256        builtin_spec=BuiltinParameterSpecs.builtin_iter_spec,
257    )
258
259
260def next_extractor(node):
261    # Split up next with and without defaults, they are not going to behave
262    # really very similar.
263    def selectNextBuiltinClass(iterator, default, source_ref):
264        if default is None:
265            return ExpressionBuiltinNext1(value=iterator, source_ref=source_ref)
266        else:
267            return ExpressionBuiltinNext2(
268                iterator=iterator, default=default, source_ref=source_ref
269            )
270
271    return BuiltinParameterSpecs.extractBuiltinArgs(
272        node=node,
273        builtin_class=selectNextBuiltinClass,
274        builtin_spec=BuiltinParameterSpecs.builtin_next_spec,
275    )
276
277
278def sum_extractor(node):
279    # Split up sumwith and without start value, one is much easier.
280    def selectSumBuiltinClass(sequence, start, source_ref):
281        if start is None:
282            return ExpressionBuiltinSum1(sequence=sequence, source_ref=source_ref)
283        else:
284            return ExpressionBuiltinSum2(
285                sequence=sequence, start=start, source_ref=source_ref
286            )
287
288    def makeSum0(source_ref):
289        # pylint: disable=unused-argument
290
291        return makeRaiseExceptionReplacementExpressionFromInstance(
292            expression=node,
293            exception=TypeError(
294                "sum expected at least 1 arguments, got 0"
295                if python_version < 0x380
296                else "sum() takes at least 1 positional argument (0 given)"
297            ),
298        )
299
300    return BuiltinParameterSpecs.extractBuiltinArgs(
301        node=node,
302        builtin_class=selectSumBuiltinClass,
303        builtin_spec=BuiltinParameterSpecs.builtin_sum_spec,
304        empty_special_class=makeSum0,
305    )
306
307
308def dict_extractor(node):
309    # The "dict" built-in is a bit strange in that it accepts a position
310    # parameter, or not, but won't have a default value.
311    def wrapExpressionBuiltinDictCreation(positional_args, dict_star_arg, source_ref):
312        if len(positional_args) > 1:
313
314            result = makeRaiseExceptionReplacementExpressionFromInstance(
315                expression=node,
316                exception=TypeError(
317                    "dict expected at most 1 arguments, got %d" % (len(positional_args))
318                ),
319            )
320
321            result = wrapExpressionWithSideEffects(
322                side_effects=positional_args, old_node=node, new_node=result
323            )
324
325            if dict_star_arg:
326                result = wrapExpressionWithSideEffects(
327                    side_effects=dict_star_arg, old_node=node, new_node=result
328                )
329
330            return result
331
332        return ExpressionBuiltinDict(
333            pos_arg=positional_args[0] if positional_args else None,
334            pairs=dict_star_arg,
335            source_ref=source_ref,
336        )
337
338    return BuiltinParameterSpecs.extractBuiltinArgs(
339        node=node,
340        builtin_class=wrapExpressionBuiltinDictCreation,
341        builtin_spec=BuiltinParameterSpecs.builtin_dict_spec,
342    )
343
344
345def chr_extractor(node):
346    return BuiltinParameterSpecs.extractBuiltinArgs(
347        node=node,
348        builtin_class=ExpressionBuiltinChr,
349        builtin_spec=BuiltinParameterSpecs.builtin_chr_spec,
350    )
351
352
353def ord_extractor(node):
354    def makeOrd0(source_ref):
355        # pylint: disable=unused-argument
356
357        return makeRaiseExceptionReplacementExpressionFromInstance(
358            expression=node,
359            exception=TypeError("ord() takes exactly one argument (0 given)"),
360        )
361
362    return BuiltinParameterSpecs.extractBuiltinArgs(
363        node=node,
364        builtin_class=ExpressionBuiltinOrd,
365        builtin_spec=BuiltinParameterSpecs.builtin_ord_spec,
366        empty_special_class=makeOrd0,
367    )
368
369
370def bin_extractor(node):
371    return BuiltinParameterSpecs.extractBuiltinArgs(
372        node=node,
373        builtin_class=ExpressionBuiltinBin,
374        builtin_spec=BuiltinParameterSpecs.builtin_bin_spec,
375    )
376
377
378def oct_extractor(node):
379    return BuiltinParameterSpecs.extractBuiltinArgs(
380        node=node,
381        builtin_class=ExpressionBuiltinOct,
382        builtin_spec=BuiltinParameterSpecs.builtin_oct_spec,
383    )
384
385
386def hex_extractor(node):
387    return BuiltinParameterSpecs.extractBuiltinArgs(
388        node=node,
389        builtin_class=ExpressionBuiltinHex,
390        builtin_spec=BuiltinParameterSpecs.builtin_hex_spec,
391    )
392
393
394def id_extractor(node):
395    return BuiltinParameterSpecs.extractBuiltinArgs(
396        node=node,
397        builtin_class=ExpressionBuiltinId,
398        builtin_spec=BuiltinParameterSpecs.builtin_id_spec,
399    )
400
401
402def repr_extractor(node):
403    return BuiltinParameterSpecs.extractBuiltinArgs(
404        node=node,
405        builtin_class=ExpressionOperationUnaryRepr,
406        builtin_spec=BuiltinParameterSpecs.builtin_repr_spec,
407    )
408
409
410if python_version >= 0x300:
411
412    def ascii_extractor(node):
413        return BuiltinParameterSpecs.extractBuiltinArgs(
414            node=node,
415            builtin_class=ExpressionBuiltinAscii,
416            builtin_spec=BuiltinParameterSpecs.builtin_repr_spec,
417        )
418
419
420def range_extractor(node):
421    def selectRangeBuiltin(low, high, step, source_ref):
422        if high is None:
423            return ExpressionBuiltinRange1(low=low, source_ref=source_ref)
424        elif step is None:
425            return ExpressionBuiltinRange2(low=low, high=high, source_ref=source_ref)
426        else:
427            return ExpressionBuiltinRange3(
428                low=low, high=high, step=step, source_ref=source_ref
429            )
430
431    def makeRange0(source_ref):
432        # pylint: disable=unused-argument
433        try:
434            range()
435        except Exception as e:  # We want to broad here, pylint: disable=broad-except
436            return makeRaiseExceptionReplacementExpressionFromInstance(
437                expression=node, exception=e
438            )
439        else:
440            raise NuitkaAssumptionError("range without argument is expected to raise")
441
442    return BuiltinParameterSpecs.extractBuiltinArgs(
443        node=node,
444        builtin_class=selectRangeBuiltin,
445        builtin_spec=BuiltinParameterSpecs.builtin_range_spec,
446        empty_special_class=makeRange0,
447    )
448
449
450def xrange_extractor(node):
451    def selectXrangeBuiltin(low, high, step, source_ref):
452        if high is None:
453            return ExpressionBuiltinXrange1(low=low, source_ref=source_ref)
454        elif step is None:
455            return ExpressionBuiltinXrange2(low=low, high=high, source_ref=source_ref)
456        else:
457            return ExpressionBuiltinXrange3(
458                low=low, high=high, step=step, source_ref=source_ref
459            )
460
461    def makeXrange0(source_ref):
462        # pylint: disable=unused-argument
463        try:
464            xrange()
465        except Exception as e:  # We want to broad here, pylint: disable=broad-except
466            return makeRaiseExceptionReplacementExpressionFromInstance(
467                expression=node, exception=e
468            )
469        else:
470            raise NuitkaAssumptionError("range without argument is expected to raise")
471
472    return BuiltinParameterSpecs.extractBuiltinArgs(
473        node=node,
474        builtin_class=selectXrangeBuiltin,
475        builtin_spec=BuiltinParameterSpecs.builtin_xrange_spec,
476        empty_special_class=makeXrange0,
477    )
478
479
480def len_extractor(node):
481    return BuiltinParameterSpecs.extractBuiltinArgs(
482        node=node,
483        builtin_class=ExpressionBuiltinLen,
484        builtin_spec=BuiltinParameterSpecs.builtin_len_spec,
485    )
486
487
488def all_extractor(node):
489    # pylint: disable=unused-argument
490    def makeAll0(source_ref):
491        exception_message = "all() takes exactly one argument (0 given)"
492
493        return makeRaiseExceptionReplacementExpressionFromInstance(
494            expression=node, exception=TypeError(exception_message)
495        )
496
497    return BuiltinParameterSpecs.extractBuiltinArgs(
498        node=node,
499        builtin_class=ExpressionBuiltinAll,
500        builtin_spec=BuiltinParameterSpecs.builtin_all_spec,
501        empty_special_class=makeAll0,
502    )
503
504
505def abs_extractor(node):
506    return BuiltinParameterSpecs.extractBuiltinArgs(
507        node=node,
508        builtin_class=ExpressionOperationUnaryAbs,
509        builtin_spec=BuiltinParameterSpecs.builtin_abs_spec,
510    )
511
512
513def any_extractor(node):
514    # pylint: disable=unused-argument
515    def makeAny0(source_ref):
516        exception_message = "any() takes exactly one argument (0 given)"
517
518        return makeRaiseExceptionReplacementExpressionFromInstance(
519            expression=node, exception=TypeError(exception_message)
520        )
521
522    return BuiltinParameterSpecs.extractBuiltinArgs(
523        node=node,
524        builtin_class=ExpressionBuiltinAny,
525        builtin_spec=BuiltinParameterSpecs.builtin_any_spec,
526        empty_special_class=makeAny0,
527    )
528
529
530def tuple_extractor(node):
531    return BuiltinParameterSpecs.extractBuiltinArgs(
532        node=node,
533        builtin_class=ExpressionBuiltinTuple,
534        builtin_spec=BuiltinParameterSpecs.builtin_tuple_spec,
535    )
536
537
538def list_extractor(node):
539    return BuiltinParameterSpecs.extractBuiltinArgs(
540        node=node,
541        builtin_class=ExpressionBuiltinList,
542        builtin_spec=BuiltinParameterSpecs.builtin_list_spec,
543    )
544
545
546def set_extractor(node):
547    return BuiltinParameterSpecs.extractBuiltinArgs(
548        node=node,
549        builtin_class=ExpressionBuiltinSet,
550        builtin_spec=BuiltinParameterSpecs.builtin_set_spec,
551    )
552
553
554def frozenset_extractor(node):
555    return BuiltinParameterSpecs.extractBuiltinArgs(
556        node=node,
557        builtin_class=ExpressionBuiltinFrozenset,
558        builtin_spec=BuiltinParameterSpecs.builtin_frozenset_spec,
559    )
560
561
562def float_extractor(node):
563    def makeFloat0(source_ref):
564        # pylint: disable=unused-argument
565
566        return makeConstantReplacementNode(
567            constant=float(), node=node, user_provided=False
568        )
569
570    return BuiltinParameterSpecs.extractBuiltinArgs(
571        node=node,
572        builtin_class=ExpressionBuiltinFloat,
573        builtin_spec=BuiltinParameterSpecs.builtin_float_spec,
574        empty_special_class=makeFloat0,
575    )
576
577
578def complex_extractor(node):
579    def makeComplex0(source_ref):
580        # pylint: disable=unused-argument
581
582        return makeConstantReplacementNode(
583            constant=complex(), node=node, user_provided=False
584        )
585
586    def selectComplexBuiltin(real, imag, source_ref):
587        if imag is None:
588            return ExpressionBuiltinComplex1(value=real, source_ref=source_ref)
589        else:
590            return ExpressionBuiltinComplex2(
591                real=real, imag=imag, source_ref=source_ref
592            )
593
594    return BuiltinParameterSpecs.extractBuiltinArgs(
595        node=node,
596        builtin_class=selectComplexBuiltin,
597        builtin_spec=BuiltinParameterSpecs.builtin_complex_spec,
598        empty_special_class=makeComplex0,
599    )
600
601
602def str_extractor(node):
603    builtin_class = ExpressionBuiltinStrP2 if str is bytes else ExpressionBuiltinStrP3
604
605    return BuiltinParameterSpecs.extractBuiltinArgs(
606        node=node,
607        builtin_class=builtin_class,
608        builtin_spec=builtin_class.builtin_spec,
609    )
610
611
612if python_version < 0x300:
613
614    def unicode_extractor(node):
615        return BuiltinParameterSpecs.extractBuiltinArgs(
616            node=node,
617            builtin_class=ExpressionBuiltinUnicodeP2,
618            builtin_spec=ExpressionBuiltinUnicodeP2.builtin_spec,
619        )
620
621
622else:
623    from nuitka.nodes.BuiltinTypeNodes import (
624        ExpressionBuiltinBytes1,
625        ExpressionBuiltinBytes3,
626    )
627
628    def bytes_extractor(node):
629        def makeBytes0(source_ref):
630            # pylint: disable=unused-argument
631
632            return makeConstantReplacementNode(
633                constant=bytes(), node=node, user_provided=False
634            )
635
636        def selectBytesBuiltin(string, encoding, errors, source_ref):
637            if encoding is None and errors is None:
638                return ExpressionBuiltinBytes1(value=string, source_ref=source_ref)
639            else:
640                return ExpressionBuiltinBytes3(
641                    value=string,
642                    encoding=encoding,
643                    errors=errors,
644                    source_ref=source_ref,
645                )
646
647        return BuiltinParameterSpecs.extractBuiltinArgs(
648            node=node,
649            builtin_class=selectBytesBuiltin,
650            builtin_spec=BuiltinParameterSpecs.builtin_bytes_p3_spec,
651            empty_special_class=makeBytes0,
652        )
653
654
655def bool_extractor(node):
656    def makeBool0(source_ref):
657        # pylint: disable=unused-argument
658
659        return makeConstantReplacementNode(
660            constant=bool(), node=node, user_provided=False
661        )
662
663    return BuiltinParameterSpecs.extractBuiltinArgs(
664        node=node,
665        builtin_class=ExpressionBuiltinBool,
666        builtin_spec=BuiltinParameterSpecs.builtin_bool_spec,
667        empty_special_class=makeBool0,
668    )
669
670
671def int_extractor(node):
672    def makeInt0(source_ref):
673        # pylint: disable=unused-argument
674
675        return makeConstantReplacementNode(
676            constant=int(), node=node, user_provided=False
677        )
678
679    def selectIntBuiltin(value, base, source_ref):
680        if base is None:
681            return ExpressionBuiltinInt1(value=value, source_ref=source_ref)
682        else:
683            return ExpressionBuiltinInt2(value=value, base=base, source_ref=source_ref)
684
685    return BuiltinParameterSpecs.extractBuiltinArgs(
686        node=node,
687        builtin_class=selectIntBuiltin,
688        builtin_spec=BuiltinParameterSpecs.builtin_int_spec,
689        empty_special_class=makeInt0,
690    )
691
692
693if python_version < 0x300:
694    from nuitka.nodes.BuiltinIntegerNodes import (
695        ExpressionBuiltinLong1,
696        ExpressionBuiltinLong2,
697    )
698
699    def long_extractor(node):
700        def makeLong0(source_ref):
701            # pylint: disable=unused-argument
702
703            return makeConstantReplacementNode(
704                constant=int(), node=node, user_provided=False
705            )
706
707        def selectIntBuiltin(value, base, source_ref):
708            if base is None:
709                return ExpressionBuiltinLong1(value=value, source_ref=source_ref)
710            else:
711                return ExpressionBuiltinLong2(
712                    value=value, base=base, source_ref=source_ref
713                )
714
715        return BuiltinParameterSpecs.extractBuiltinArgs(
716            node=node,
717            builtin_class=selectIntBuiltin,
718            builtin_spec=BuiltinParameterSpecs.builtin_int_spec,
719            empty_special_class=makeLong0,
720        )
721
722
723def globals_extractor(node):
724    return BuiltinParameterSpecs.extractBuiltinArgs(
725        node=node,
726        builtin_class=ExpressionBuiltinGlobals,
727        builtin_spec=BuiltinParameterSpecs.builtin_globals_spec,
728    )
729
730
731def locals_extractor(node):
732    locals_scope = node.subnode_called.getLocalsScope()
733
734    def makeLocalsNode(source_ref):
735        return makeExpressionBuiltinLocals(
736            locals_scope=locals_scope, source_ref=source_ref
737        )
738
739    # Note: Locals on the module level is really globals.
740    return BuiltinParameterSpecs.extractBuiltinArgs(
741        node=node,
742        builtin_class=makeLocalsNode,
743        builtin_spec=BuiltinParameterSpecs.builtin_locals_spec,
744    )
745
746
747if python_version < 0x300:
748    from nuitka.nodes.ExecEvalNodes import ExpressionBuiltinExecfile
749
750    def execfile_extractor(node):
751        def wrapExpressionBuiltinExecfileCreation(
752            filename, globals_arg, locals_arg, source_ref
753        ):
754            outline_body = ExpressionOutlineBody(
755                provider=node.getParentVariableProvider(),
756                name="execfile_call",
757                source_ref=source_ref,
758            )
759
760            globals_ref, locals_ref, tried, final = wrapEvalGlobalsAndLocals(
761                provider=node.getParentVariableProvider(),
762                globals_node=globals_arg,
763                locals_node=locals_arg,
764                temp_scope=outline_body.getOutlineTempScope(),
765                source_ref=source_ref,
766            )
767
768            tried = makeStatementsSequence(
769                statements=(
770                    tried,
771                    makeStatementReturn(
772                        expression=ExpressionBuiltinExecfile(
773                            source_code=makeCallNode(
774                                ExpressionAttributeLookup(
775                                    expression=ExpressionBuiltinOpen(
776                                        filename=filename,
777                                        mode=makeConstantRefNode(
778                                            constant="rU", source_ref=source_ref
779                                        ),
780                                        buffering=None,
781                                        source_ref=source_ref,
782                                    ),
783                                    attribute_name="read",
784                                    source_ref=source_ref,
785                                ),
786                                source_ref,
787                            ),
788                            globals_arg=globals_ref,
789                            locals_arg=locals_ref,
790                            source_ref=source_ref,
791                        ),
792                        source_ref=source_ref,
793                    ),
794                ),
795                allow_none=False,
796                source_ref=source_ref,
797            )
798
799            outline_body.setChild(
800                "body",
801                makeStatementsSequenceFromStatement(
802                    statement=makeTryFinallyStatement(
803                        provider=outline_body,
804                        tried=tried,
805                        final=final,
806                        source_ref=source_ref,
807                    )
808                ),
809            )
810
811            return outline_body
812
813        return BuiltinParameterSpecs.extractBuiltinArgs(
814            node=node,
815            builtin_class=wrapExpressionBuiltinExecfileCreation,
816            builtin_spec=BuiltinParameterSpecs.builtin_execfile_spec,
817        )
818
819
820def eval_extractor(node):
821    def wrapEvalBuiltin(source, globals_arg, locals_arg, source_ref):
822        provider = node.getParentVariableProvider()
823
824        outline_body = ExpressionOutlineBody(
825            provider=node.getParentVariableProvider(),
826            name="eval_call",
827            source_ref=source_ref,
828        )
829
830        globals_ref, locals_ref, tried, final = wrapEvalGlobalsAndLocals(
831            provider=provider,
832            globals_node=globals_arg,
833            locals_node=locals_arg,
834            temp_scope=outline_body.getOutlineTempScope(),
835            source_ref=source_ref,
836        )
837
838        # The wrapping should not relocate to the "source_ref".
839        assert (
840            globals_arg is None
841            or globals_ref.getSourceReference() == globals_arg.getSourceReference()
842        )
843        assert (
844            locals_arg is None
845            or locals_ref.getSourceReference() == locals_arg.getSourceReference()
846        )
847
848        source_variable = outline_body.allocateTempVariable(
849            temp_scope=None, name="source"
850        )
851
852        final.setChild(
853            "statements",
854            final.subnode_statements
855            + (
856                StatementDelVariable(
857                    variable=source_variable, tolerant=True, source_ref=source_ref
858                ),
859            ),
860        )
861
862        strip_choice = makeConstantRefNode(constant=(" \t",), source_ref=source_ref)
863
864        if python_version >= 0x300:
865            strip_choice = ExpressionConditional(
866                condition=ExpressionComparisonIs(
867                    left=ExpressionBuiltinType1(
868                        value=ExpressionTempVariableRef(
869                            variable=source_variable, source_ref=source_ref
870                        ),
871                        source_ref=source_ref,
872                    ),
873                    right=makeExpressionBuiltinTypeRef(
874                        builtin_name="bytes", source_ref=source_ref
875                    ),
876                    source_ref=source_ref,
877                ),
878                expression_yes=makeConstantRefNode(
879                    constant=(b" \t",), source_ref=source_ref
880                ),
881                expression_no=strip_choice,
882                source_ref=source_ref,
883            )
884
885        # Source needs some special treatment for eval, if it's a string, it
886        # must be stripped.
887        string_fixup = StatementAssignmentVariable(
888            variable=source_variable,
889            source=makeExpressionCall(
890                called=ExpressionAttributeLookup(
891                    expression=ExpressionTempVariableRef(
892                        variable=source_variable, source_ref=source_ref
893                    ),
894                    attribute_name="strip",
895                    source_ref=source_ref,
896                ),
897                args=strip_choice,  # This is a tuple
898                kw=None,
899                source_ref=source_ref,
900            ),
901            source_ref=source_ref,
902        )
903
904        acceptable_builtin_types = [
905            ExpressionBuiltinAnonymousRef(builtin_name="code", source_ref=source_ref)
906        ]
907
908        if python_version >= 0x270:
909            acceptable_builtin_types.append(
910                makeExpressionBuiltinTypeRef(
911                    builtin_name="memoryview", source_ref=source_ref
912                )
913            )
914
915        statements = (
916            StatementAssignmentVariable(
917                variable=source_variable, source=source, source_ref=source_ref
918            ),
919            makeStatementConditional(
920                condition=ExpressionOperationNot(
921                    operand=ExpressionBuiltinIsinstance(
922                        instance=ExpressionTempVariableRef(
923                            variable=source_variable, source_ref=source_ref
924                        ),
925                        classes=makeExpressionMakeTupleOrConstant(
926                            elements=acceptable_builtin_types,
927                            user_provided=True,
928                            source_ref=source_ref,
929                        ),
930                        source_ref=source_ref,
931                    ),
932                    source_ref=source_ref,
933                ),
934                yes_branch=string_fixup,
935                no_branch=None,
936                source_ref=source_ref,
937            ),
938            makeStatementReturn(
939                expression=ExpressionBuiltinEval(
940                    source_code=ExpressionTempVariableRef(
941                        variable=source_variable, source_ref=source_ref
942                    ),
943                    globals_arg=globals_ref,
944                    locals_arg=locals_ref,
945                    source_ref=source_ref,
946                ),
947                source_ref=source_ref,
948            ),
949        )
950
951        tried = makeStatementsSequence(
952            statements=(tried,) + statements, allow_none=False, source_ref=source_ref
953        )
954
955        outline_body.setChild(
956            "body",
957            makeStatementsSequenceFromStatement(
958                statement=makeTryFinallyStatement(
959                    provider=outline_body,
960                    tried=tried,
961                    final=final,
962                    source_ref=source_ref,
963                )
964            ),
965        )
966
967        return outline_body
968
969    return BuiltinParameterSpecs.extractBuiltinArgs(
970        node=node,
971        builtin_class=wrapEvalBuiltin,
972        builtin_spec=BuiltinParameterSpecs.builtin_eval_spec,
973    )
974
975
976if python_version >= 0x300:
977    from nuitka.nodes.ExecEvalNodes import ExpressionBuiltinExec
978
979    def exec_extractor(node):
980        def wrapExpressionBuiltinExecCreation(
981            source, globals_arg, locals_arg, source_ref
982        ):
983            provider = node.getParentVariableProvider()
984
985            outline_body = ExpressionOutlineBody(
986                provider=provider, name="exec_call", source_ref=source_ref
987            )
988
989            globals_ref, locals_ref, tried, final = wrapEvalGlobalsAndLocals(
990                provider=provider,
991                globals_node=globals_arg,
992                locals_node=locals_arg,
993                temp_scope=outline_body.getOutlineTempScope(),
994                source_ref=source_ref,
995            )
996
997            tried = makeStatementsSequence(
998                statements=(
999                    tried,
1000                    makeStatementReturn(
1001                        expression=ExpressionBuiltinExec(
1002                            source_code=source,
1003                            globals_arg=globals_ref,
1004                            locals_arg=locals_ref,
1005                            source_ref=source_ref,
1006                        ),
1007                        source_ref=source_ref,
1008                    ),
1009                ),
1010                allow_none=False,
1011                source_ref=source_ref,
1012            )
1013
1014            # Hack: Allow some APIs to work already
1015            tried.parent = outline_body
1016
1017            outline_body.setChild(
1018                "body",
1019                makeStatementsSequenceFromStatement(
1020                    statement=makeTryFinallyStatement(
1021                        provider=provider,
1022                        tried=tried,
1023                        final=final,
1024                        source_ref=source_ref,
1025                    )
1026                ),
1027            )
1028
1029            return outline_body
1030
1031        return BuiltinParameterSpecs.extractBuiltinArgs(
1032            node=node,
1033            builtin_class=wrapExpressionBuiltinExecCreation,
1034            builtin_spec=BuiltinParameterSpecs.builtin_eval_spec,
1035        )
1036
1037
1038def compile_extractor(node):
1039    def wrapExpressionBuiltinCompileCreation(
1040        source_code, filename, mode, flags, dont_inherit, optimize=None, source_ref=None
1041    ):
1042        return ExpressionBuiltinCompile(
1043            source_code=source_code,
1044            filename=filename,
1045            mode=mode,
1046            flags=flags,
1047            dont_inherit=dont_inherit,
1048            optimize=optimize,
1049            source_ref=source_ref,
1050        )
1051
1052    return BuiltinParameterSpecs.extractBuiltinArgs(
1053        node=node,
1054        builtin_class=wrapExpressionBuiltinCompileCreation,
1055        builtin_spec=BuiltinParameterSpecs.builtin_compile_spec,
1056    )
1057
1058
1059def open_extractor(node):
1060    def makeOpen0(source_ref):
1061        # pylint: disable=unused-argument
1062        try:
1063            open()
1064        except Exception as e:  # We want to broad here, pylint: disable=broad-except
1065            return makeRaiseExceptionReplacementExpressionFromInstance(
1066                expression=node, exception=e
1067            )
1068        else:
1069            raise NuitkaAssumptionError("open without argument is expected to raise")
1070
1071    return BuiltinParameterSpecs.extractBuiltinArgs(
1072        node=node,
1073        builtin_class=ExpressionBuiltinOpen,
1074        builtin_spec=BuiltinParameterSpecs.builtin_open_spec,
1075        empty_special_class=makeOpen0,
1076    )
1077
1078
1079def super_extractor(node):
1080    def wrapSuperBuiltin(type_arg, object_arg, source_ref):
1081        if type_arg is None and python_version >= 0x300:
1082            if provider.isCompiledPythonModule():
1083                return makeRaiseExceptionReplacementExpression(
1084                    expression=node,
1085                    exception_type="RuntimeError",
1086                    exception_value="super(): no arguments",
1087                )
1088
1089            class_variable = provider.getVariableForReference(variable_name="__class__")
1090
1091            provider.trace_collection.getVariableCurrentTrace(class_variable).addUsage()
1092
1093            type_arg = ExpressionVariableRef(
1094                # Ought to be already closure taken due to "super" flag in
1095                # tree building.
1096                variable=class_variable,
1097                source_ref=source_ref,
1098            )
1099
1100            # If we already have this as a local variable, then use that
1101            # instead.
1102            type_arg_owner = class_variable.getOwner()
1103            if type_arg_owner is provider or not (
1104                type_arg_owner.isExpressionFunctionBody()
1105                or type_arg_owner.isExpressionClassBody()
1106            ):
1107                return makeRaiseExceptionReplacementExpression(
1108                    expression=node,
1109                    exception_type="SystemError"
1110                    if python_version < 0x331
1111                    else "RuntimeError",
1112                    exception_value="super(): __class__ cell not found",
1113                )
1114
1115            if object_arg is None:
1116                if (
1117                    provider.isExpressionGeneratorObjectBody()
1118                    or provider.isExpressionCoroutineObjectBody()
1119                    or provider.isExpressionAsyncgenObjectBody()
1120                ):
1121                    parameter_provider = provider.getParentVariableProvider()
1122                else:
1123                    parameter_provider = provider
1124
1125                if parameter_provider.getParameters().getArgumentCount() == 0:
1126                    return makeRaiseExceptionReplacementExpression(
1127                        expression=node,
1128                        exception_type="RuntimeError",
1129                        exception_value="super(): no arguments",
1130                    )
1131                else:
1132                    par1_name = parameter_provider.getParameters().getArgumentNames()[0]
1133
1134                    object_variable = provider.getVariableForReference(
1135                        variable_name=par1_name
1136                    )
1137
1138                    provider.trace_collection.getVariableCurrentTrace(
1139                        object_variable
1140                    ).addUsage()
1141
1142                    object_arg = ExpressionVariableRef(
1143                        variable=object_variable, source_ref=source_ref
1144                    )
1145
1146                    if not object_arg.getVariable().isParameterVariable():
1147                        return makeRaiseExceptionReplacementExpression(
1148                            expression=node,
1149                            exception_type="SystemError"
1150                            if python_version < 0x300
1151                            else "RuntimeError",
1152                            exception_value="super(): __class__ cell not found",
1153                        )
1154
1155            return ExpressionBuiltinSuper0(
1156                type_arg=type_arg, object_arg=object_arg, source_ref=source_ref
1157            )
1158
1159        return ExpressionBuiltinSuper2(
1160            type_arg=type_arg, object_arg=object_arg, source_ref=source_ref
1161        )
1162
1163    provider = node.getParentVariableProvider().getEntryPoint()
1164
1165    if not provider.isCompiledPythonModule():
1166        provider.discardFlag("has_super")
1167
1168    return BuiltinParameterSpecs.extractBuiltinArgs(
1169        node=node,
1170        builtin_class=wrapSuperBuiltin,
1171        builtin_spec=BuiltinParameterSpecs.builtin_super_spec,
1172    )
1173
1174
1175def hasattr_extractor(node):
1176    # We need to have to builtin arguments, pylint: disable=redefined-builtin
1177    def makeExpressionBuiltinHasattr(object, name, source_ref):
1178        return ExpressionBuiltinHasattr(
1179            expression=object, name=name, source_ref=source_ref
1180        )
1181
1182    return BuiltinParameterSpecs.extractBuiltinArgs(
1183        node=node,
1184        builtin_class=makeExpressionBuiltinHasattr,
1185        builtin_spec=BuiltinParameterSpecs.builtin_hasattr_spec,
1186    )
1187
1188
1189def getattr_extractor(node):
1190    # We need to have to builtin arguments, pylint: disable=redefined-builtin
1191    def makeExpressionBuiltinGetattr(object, name, default, source_ref):
1192        return ExpressionBuiltinGetattr(
1193            expression=object, name=name, default=default, source_ref=source_ref
1194        )
1195
1196    return BuiltinParameterSpecs.extractBuiltinArgs(
1197        node=node,
1198        builtin_class=makeExpressionBuiltinGetattr,
1199        builtin_spec=BuiltinParameterSpecs.builtin_getattr_spec,
1200    )
1201
1202
1203def setattr_extractor(node):
1204    # We need to have to builtin arguments, pylint: disable=redefined-builtin
1205    def makeExpressionBuiltinSetattr(object, name, value, source_ref):
1206        return ExpressionBuiltinSetattr(
1207            expression=object, name=name, value=value, source_ref=source_ref
1208        )
1209
1210    return BuiltinParameterSpecs.extractBuiltinArgs(
1211        node=node,
1212        builtin_class=makeExpressionBuiltinSetattr,
1213        builtin_spec=BuiltinParameterSpecs.builtin_setattr_spec,
1214    )
1215
1216
1217def isinstance_extractor(node):
1218    return BuiltinParameterSpecs.extractBuiltinArgs(
1219        node=node,
1220        builtin_class=ExpressionBuiltinIsinstance,
1221        builtin_spec=BuiltinParameterSpecs.builtin_isinstance_spec,
1222    )
1223
1224
1225def issubclass_extractor(node):
1226    return BuiltinParameterSpecs.extractBuiltinArgs(
1227        node=node,
1228        builtin_class=ExpressionBuiltinIssubclass,
1229        builtin_spec=BuiltinParameterSpecs.builtin_isinstance_spec,
1230    )
1231
1232
1233def bytearray_extractor(node):
1234    def makeBytearray0(source_ref):
1235        return makeConstantRefNode(constant=bytearray(), source_ref=source_ref)
1236
1237    def selectNextBuiltinClass(string, encoding, errors, source_ref):
1238        if encoding is None:
1239            return ExpressionBuiltinBytearray1(value=string, source_ref=source_ref)
1240        else:
1241            return ExpressionBuiltinBytearray3(
1242                string=string, encoding=encoding, errors=errors, source_ref=source_ref
1243            )
1244
1245    return BuiltinParameterSpecs.extractBuiltinArgs(
1246        node=node,
1247        builtin_class=selectNextBuiltinClass,
1248        builtin_spec=BuiltinParameterSpecs.builtin_bytearray_spec,
1249        empty_special_class=makeBytearray0,
1250    )
1251
1252
1253def slice_extractor(node):
1254    def wrapSlice(start, stop, step, source_ref):
1255        if start is not None and stop is None:
1256            # Default rules are strange. If one argument is given, it's the
1257            # second one then.
1258            stop = start
1259            start = None
1260
1261        return makeExpressionBuiltinSlice(
1262            start=start, stop=stop, step=step, source_ref=source_ref
1263        )
1264
1265    return BuiltinParameterSpecs.extractBuiltinArgs(
1266        node=node,
1267        builtin_class=wrapSlice,
1268        builtin_spec=BuiltinParameterSpecs.builtin_slice_spec,
1269    )
1270
1271
1272def hash_extractor(node):
1273    return BuiltinParameterSpecs.extractBuiltinArgs(
1274        node=node,
1275        builtin_class=ExpressionBuiltinHash,
1276        builtin_spec=BuiltinParameterSpecs.builtin_hash_spec,
1277    )
1278
1279
1280def format_extractor(node):
1281    def makeFormat0(source_ref):
1282        # pylint: disable=unused-argument
1283
1284        return makeRaiseExceptionReplacementExpressionFromInstance(
1285            expression=node,
1286            exception=TypeError("format() takes at least 1 argument (0 given)"),
1287        )
1288
1289    return BuiltinParameterSpecs.extractBuiltinArgs(
1290        node=node,
1291        builtin_class=ExpressionBuiltinFormat,
1292        builtin_spec=BuiltinParameterSpecs.builtin_format_spec,
1293        empty_special_class=makeFormat0,
1294    )
1295
1296
1297def staticmethod_extractor(node):
1298    def makeStaticmethod0(source_ref):
1299        # pylint: disable=unused-argument
1300
1301        return makeRaiseExceptionReplacementExpressionFromInstance(
1302            expression=node,
1303            exception=TypeError("staticmethod expected 1 arguments, got 0"),
1304        )
1305
1306    return BuiltinParameterSpecs.extractBuiltinArgs(
1307        node=node,
1308        builtin_class=ExpressionBuiltinStaticmethod,
1309        builtin_spec=BuiltinParameterSpecs.builtin_staticmethod_spec,
1310        empty_special_class=makeStaticmethod0,
1311    )
1312
1313
1314def classmethod_extractor(node):
1315    def makeStaticmethod0(source_ref):
1316        # pylint: disable=unused-argument
1317
1318        return makeRaiseExceptionReplacementExpressionFromInstance(
1319            expression=node,
1320            exception=TypeError("classmethod expected 1 arguments, got 0"),
1321        )
1322
1323    return BuiltinParameterSpecs.extractBuiltinArgs(
1324        node=node,
1325        builtin_class=ExpressionBuiltinClassmethod,
1326        builtin_spec=BuiltinParameterSpecs.builtin_classmethod_spec,
1327        empty_special_class=makeStaticmethod0,
1328    )
1329
1330
1331def divmod_extractor(node):
1332    return BuiltinParameterSpecs.extractBuiltinArgs(
1333        node=node,
1334        builtin_class=ExpressionOperationBinaryDivmod,
1335        builtin_spec=BuiltinParameterSpecs.builtin_divmod_spec,
1336    )
1337
1338
1339_dispatch_dict = {
1340    "compile": compile_extractor,
1341    "globals": globals_extractor,
1342    "locals": locals_extractor,
1343    "eval": eval_extractor,
1344    "dir": dir_extractor,
1345    "vars": vars_extractor,
1346    "__import__": import_extractor,
1347    "chr": chr_extractor,
1348    "ord": ord_extractor,
1349    "bin": bin_extractor,
1350    "oct": oct_extractor,
1351    "hex": hex_extractor,
1352    "id": id_extractor,
1353    "type": type_extractor,
1354    "iter": iter_extractor,
1355    "next": next_extractor,
1356    "sum": sum_extractor,
1357    "tuple": tuple_extractor,
1358    "list": list_extractor,
1359    "dict": dict_extractor,
1360    "set": set_extractor,
1361    "frozenset": frozenset_extractor,
1362    "float": float_extractor,
1363    "complex": complex_extractor,
1364    "str": str_extractor,
1365    "bool": bool_extractor,
1366    "int": int_extractor,
1367    "repr": repr_extractor,
1368    "len": len_extractor,
1369    "any": any_extractor,
1370    "abs": abs_extractor,
1371    "all": all_extractor,
1372    "super": super_extractor,
1373    "hasattr": hasattr_extractor,
1374    "getattr": getattr_extractor,
1375    "setattr": setattr_extractor,
1376    "isinstance": isinstance_extractor,
1377    "issubclass": issubclass_extractor,
1378    "bytearray": bytearray_extractor,
1379    "slice": slice_extractor,
1380    "hash": hash_extractor,
1381    "format": format_extractor,
1382    "open": open_extractor,
1383    "staticmethod": staticmethod_extractor,
1384    "classmethod": classmethod_extractor,
1385    "divmod": divmod_extractor,
1386}
1387
1388if python_version < 0x300:
1389    # These are not in Python3
1390    _dispatch_dict["long"] = long_extractor
1391    _dispatch_dict["unicode"] = unicode_extractor
1392    _dispatch_dict["execfile"] = execfile_extractor
1393    _dispatch_dict["xrange"] = xrange_extractor
1394
1395    _dispatch_dict["range"] = range_extractor
1396else:
1397    # This one is not in Python2:
1398    _dispatch_dict["bytes"] = bytes_extractor
1399    _dispatch_dict["ascii"] = ascii_extractor
1400    _dispatch_dict["exec"] = exec_extractor
1401
1402    # The Python3 range is really an xrange, use that.
1403    _dispatch_dict["range"] = xrange_extractor
1404
1405
1406def check():
1407    from nuitka.Builtins import builtin_names
1408
1409    for builtin_name in _dispatch_dict:
1410        assert builtin_name in builtin_names, builtin_name
1411
1412
1413check()
1414
1415_builtin_ignore_list = (
1416    # Not supporting 'print', because it could be replaced, and is not
1417    # worth the effort yet.
1418    "print",
1419    # TODO: This could, and should be supported, as we could e.g. lower
1420    # types easily for it.
1421    "sorted",
1422    # TODO: This would be very worthwhile, as it could easily optimize
1423    # its iteration away.
1424    "zip",
1425    # TODO: This would be most precious due to the type hint it gives
1426    "enumerate",
1427    # TODO: Also worthwhile for known values.
1428    "reversed",
1429    # TODO: Not sure what this really is about.
1430    "memoryview",
1431)
1432
1433
1434def _describeNewNode(builtin_name, inspect_node):
1435    """Describe the change for better understanding."""
1436
1437    # Don't mention side effects, that's not what we care about.
1438    if inspect_node.isExpressionSideEffects():
1439        inspect_node = inspect_node.subnode_expression
1440
1441    if inspect_node.isExpressionBuiltinImport():
1442        tags = "new_import"
1443        message = """\
1444Replaced dynamic "__import__" call with static built-in call."""
1445    elif inspect_node.isExpressionBuiltin() or inspect_node.isStatementExec():
1446        tags = "new_builtin"
1447        message = "Replaced call to built-in '%s' with built-in call '%s'." % (
1448            builtin_name,
1449            inspect_node.kind,
1450        )
1451    elif inspect_node.isExpressionRaiseException():
1452        tags = "new_raise"
1453        message = """\
1454Replaced call to built-in '%s' with exception raise.""" % (
1455            builtin_name,
1456        )
1457    elif inspect_node.isExpressionOperationBinary():
1458        tags = "new_expression"
1459        message = """\
1460Replaced call to built-in '%s' with binary operation '%s'.""" % (
1461            builtin_name,
1462            inspect_node.getOperator(),
1463        )
1464    elif inspect_node.isExpressionOperationUnary():
1465        tags = "new_expression"
1466        message = """\
1467Replaced call to built-in '%s' with unary operation '%s'.""" % (
1468            builtin_name,
1469            inspect_node.getOperator(),
1470        )
1471    elif inspect_node.isExpressionCall():
1472        tags = "new_expression"
1473        message = """\
1474Replaced call to built-in '%s' with call.""" % (
1475            builtin_name,
1476        )
1477    elif inspect_node.isExpressionOutlineBody():
1478        tags = "new_expression"
1479        message = (
1480            """\
1481Replaced call to built-in '%s' with outlined call."""
1482            % builtin_name
1483        )
1484    elif inspect_node.isExpressionConstantRef():
1485        tags = "new_expression"
1486        message = (
1487            """\
1488Replaced call to built-in '%s' with constant value."""
1489            % builtin_name
1490        )
1491    else:
1492        assert False, (builtin_name, "->", inspect_node)
1493
1494    return tags, message
1495
1496
1497def computeBuiltinCall(builtin_name, call_node):
1498    # There is some dispatching for how to output various types of changes,
1499    # with lots of cases.
1500    if builtin_name in _dispatch_dict:
1501        new_node = _dispatch_dict[builtin_name](call_node)
1502
1503        assert new_node is not call_node, builtin_name
1504        assert new_node is not None, builtin_name
1505
1506        # For traces, we are going to ignore side effects, and output traces
1507        # only based on the basis of it.
1508        tags, message = _describeNewNode(builtin_name, new_node)
1509
1510        return new_node, tags, message
1511    else:
1512        # TODO: Achieve coverage of all built-ins in at least the ignore list.
1513        # if False and builtin_name not in _builtin_ignore_list:
1514        #     optimization_logger.warning(
1515        #         "Not handling built-in %r, consider support." % builtin_name
1516        #     )
1517
1518        return call_node, None, None
1519