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""" Format related nodes format/bin/oct/hex/ascii.
19
20These will most often be used for outputs, and the hope is, the type prediction or the
21result prediction will help to be smarter, but generally these should not be that much
22about performance critical.
23
24"""
25from nuitka.PythonVersions import python_version
26from nuitka.specs import BuiltinParameterSpecs
27
28from .ExpressionBases import (
29    ExpressionBuiltinSingleArgBase,
30    ExpressionChildrenHavingBase,
31)
32from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode
33from .shapes.BuiltinTypeShapes import (
34    tshape_int_or_long,
35    tshape_str,
36    tshape_str_or_unicode,
37)
38
39
40class ExpressionBuiltinFormat(ExpressionChildrenHavingBase):
41    kind = "EXPRESSION_BUILTIN_FORMAT"
42
43    named_children = ("value", "format_spec")
44
45    # Using slots, they don't need that
46    # pylint: disable=access-member-before-definition,attribute-defined-outside-init
47
48    def __init__(self, value, format_spec, source_ref):
49        ExpressionChildrenHavingBase.__init__(
50            self,
51            values={"value": value, "format_spec": format_spec},
52            source_ref=source_ref,
53        )
54
55    @staticmethod
56    def getTypeShape():
57        return tshape_str_or_unicode
58
59    def computeExpression(self, trace_collection):
60        # TODO: Can use the format built-in on compile time constants at least.
61
62        value = self.subnode_value
63        format_spec = self.subnode_format_spec
64
65        # Go to default way if possible.
66        if format_spec is not None and format_spec.isExpressionConstantStrEmptyRef():
67            self.subnode_format_spec = None
68            format_spec = None
69
70        # Strings format themselves as what they are.
71        if format_spec is None:
72            if value.hasShapeStrExact() or value.hasShapeUnicodeExact():
73                return (
74                    value,
75                    "new_expression",
76                    """\
77Removed useless 'format' on '%s' value."""
78                    % value.getTypeShape().getTypeName(),
79                )
80
81        # TODO: Provide "__format__" slot based handling.
82
83        # Any code could be run, note that.
84        trace_collection.onControlFlowEscape(self)
85
86        # Any exception may be raised.
87        trace_collection.onExceptionRaiseExit(BaseException)
88
89        return self, None, None
90
91
92class ExpressionBuiltinAscii(ExpressionBuiltinSingleArgBase):
93    kind = "EXPRESSION_BUILTIN_ASCII"
94
95    if python_version >= 0x300:
96        builtin_spec = BuiltinParameterSpecs.builtin_ascii_spec
97
98    @staticmethod
99    def getTypeShape():
100        return tshape_str
101
102
103class ExpressionBuiltinBin(ExpressionBuiltinSingleArgBase):
104    kind = "EXPRESSION_BUILTIN_BIN"
105
106    builtin_spec = BuiltinParameterSpecs.builtin_bin_spec
107
108    @staticmethod
109    def getTypeShape():
110        return tshape_str
111
112
113class ExpressionBuiltinOct(ExpressionBuiltinSingleArgBase):
114    kind = "EXPRESSION_BUILTIN_OCT"
115
116    builtin_spec = BuiltinParameterSpecs.builtin_oct_spec
117
118    @staticmethod
119    def getTypeShape():
120        return tshape_str
121
122
123class ExpressionBuiltinHex(ExpressionBuiltinSingleArgBase):
124    kind = "EXPRESSION_BUILTIN_HEX"
125
126    builtin_spec = BuiltinParameterSpecs.builtin_hex_spec
127
128    @staticmethod
129    def getTypeShape():
130        return tshape_str
131
132
133class ExpressionBuiltinId(ExpressionBuiltinSingleArgBase):
134    kind = "EXPRESSION_BUILTIN_ID"
135
136    builtin_spec = BuiltinParameterSpecs.builtin_id_spec
137
138    def computeExpression(self, trace_collection):
139        # Note: Quite impossible to predict the pointer value or anything, but
140        # we know the result will be a long.
141        return self, None, None
142
143    def mayRaiseException(self, exception_type):
144        return self.subnode_value.mayRaiseException(exception_type)
145
146    def getIntValue(self):
147        return self
148
149    @staticmethod
150    def getTypeShape():
151        return tshape_int_or_long
152
153    def computeExpressionDrop(self, statement, trace_collection):
154        result = makeStatementExpressionOnlyReplacementNode(
155            expression=self.subnode_value, node=self
156        )
157
158        del self.parent
159
160        return (
161            result,
162            "new_statements",
163            """\
164Removed id taking for unused result.""",
165        )
166
167    def mayHaveSideEffects(self):
168        return self.subnode_value.mayHaveSideEffects()
169
170    def extractSideEffects(self):
171        return (self.subnode_value,)
172