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""" Node for the calls to the 'int' and 'long' (Python2) built-ins.
19
20These are divided into variants for one and two arguments and they have a
21common base class, because most of the behavior is the same there. The ones
22with 2 arguments only work on strings, and give errors otherwise, the ones
23with one argument, use slots, "__int__" and "__long__", so what they do does
24largely depend on the arguments slot.
25"""
26
27from nuitka.__past__ import long  # pylint: disable=I0021,redefined-builtin
28from nuitka.PythonVersions import python_version
29from nuitka.specs import BuiltinParameterSpecs
30
31from .ConstantRefNodes import makeConstantRefNode
32from .ExpressionBases import (
33    ExpressionChildHavingBase,
34    ExpressionChildrenHavingBase,
35    ExpressionSpecBasedComputationMixin,
36)
37from .shapes.BuiltinTypeShapes import (
38    tshape_int_or_long,
39    tshape_int_or_long_derived,
40    tshape_long,
41    tshape_long_derived,
42)
43
44
45class ExpressionBuiltinInt1(ExpressionChildHavingBase):
46    kind = "EXPRESSION_BUILTIN_INT1"
47
48    named_child = "value"
49
50    def __init__(self, value, source_ref):
51        ExpressionChildHavingBase.__init__(self, value=value, source_ref=source_ref)
52
53    @staticmethod
54    def getTypeShape():
55        # TODO: Depending on input type shape and value, we should improve this.
56        return tshape_int_or_long_derived
57
58    def computeExpression(self, trace_collection):
59        return self.subnode_value.computeExpressionInt(
60            int_node=self, trace_collection=trace_collection
61        )
62
63    def mayRaiseException(self, exception_type):
64        return self.subnode_value.mayRaiseExceptionInt(exception_type)
65
66
67class ExpressionBuiltinIntLong2Base(
68    ExpressionSpecBasedComputationMixin, ExpressionChildrenHavingBase
69):
70    named_children = ("value", "base")
71
72    # Note: Version specific, may be allowed or not.
73    try:
74        int(base=2)
75    except TypeError:
76        base_only_value = False
77    else:
78        base_only_value = True
79
80    # To be overloaded by child classes with int/long.
81    builtin = int
82
83    def __init__(self, value, base, source_ref):
84        if value is None and self.base_only_value:
85            value = makeConstantRefNode(
86                constant="0", source_ref=source_ref, user_provided=True
87            )
88
89        ExpressionChildrenHavingBase.__init__(
90            self, values={"value": value, "base": base}, source_ref=source_ref
91        )
92
93    def computeExpression(self, trace_collection):
94        value = self.subnode_value
95        base = self.subnode_base
96
97        if value is None:
98            if base is not None:
99                if not self.base_only_value:
100                    return trace_collection.getCompileTimeComputationResult(
101                        node=self,
102                        computation=lambda: self.builtin(base=2),
103                        description="""\
104%s built-in call with only base argument"""
105                        % self.builtin.__name__,
106                    )
107
108            given_values = ()
109        else:
110            given_values = (value, base)
111
112        return self.computeBuiltinSpec(
113            trace_collection=trace_collection, given_values=given_values
114        )
115
116
117class ExpressionBuiltinInt2(ExpressionBuiltinIntLong2Base):
118    kind = "EXPRESSION_BUILTIN_INT2"
119
120    builtin_spec = BuiltinParameterSpecs.builtin_int_spec
121    builtin = int
122
123    @staticmethod
124    def getTypeShape():
125        return tshape_int_or_long
126
127
128if python_version < 0x300:
129
130    class ExpressionBuiltinLong1(ExpressionChildHavingBase):
131        kind = "EXPRESSION_BUILTIN_LONG1"
132
133        named_child = "value"
134
135        def __init__(self, value, source_ref):
136            ExpressionChildHavingBase.__init__(self, value=value, source_ref=source_ref)
137
138        @staticmethod
139        def getTypeShape():
140            # TODO: Depending on input type shape and value, we should improve this.
141            return tshape_long_derived
142
143        def computeExpression(self, trace_collection):
144            return self.subnode_value.computeExpressionLong(
145                long_node=self, trace_collection=trace_collection
146            )
147
148        def mayRaiseException(self, exception_type):
149            return self.subnode_value.mayRaiseExceptionLong(exception_type)
150
151    class ExpressionBuiltinLong2(ExpressionBuiltinIntLong2Base):
152        kind = "EXPRESSION_BUILTIN_LONG2"
153
154        builtin_spec = BuiltinParameterSpecs.builtin_long_spec
155        builtin = long
156
157        @staticmethod
158        def getTypeShape():
159            return tshape_long
160