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 subscript into slicing.
19
20For Python2, there is a difference between x[a], x[a:b], x[a:b:c] whereas
21Python3 treats the later by making a slice object, Python2 tries to have
22special slice access, if available, or building a slice object only at the
23end.
24
25Consult the developer manual for information. TODO: Add ability to sync
26source code comments with developer manual sections.
27"""
28
29from nuitka.nodes.ConstantRefNodes import ExpressionConstantEllipsisRef
30from nuitka.nodes.SliceNodes import (
31    ExpressionSliceLookup,
32    makeExpressionBuiltinSlice,
33)
34from nuitka.nodes.SubscriptNodes import ExpressionSubscriptLookup
35from nuitka.PythonVersions import python_version
36
37from .ReformulationAssignmentStatements import buildExtSliceNode
38from .TreeHelpers import buildNode, getKind
39
40
41def buildSubscriptNode(provider, node, source_ref):
42    # Subscript expression nodes, various types are dispatched here.
43
44    assert getKind(node.ctx) == "Load", source_ref
45
46    # The subscript "[]" operator is one of many different things. This is
47    # expressed by this kind, there are "slice" lookups (two values, even if one
48    # is using default), and then "index" lookups. The form with three argument
49    # is really an "index" lookup, with a slice object. And the "..." lookup is
50    # also an index loop-up, with it as the argument. So this splits things into
51    # two different operations, "subscript" with a single "subscript" object. Or
52    # a slice lookup with a lower and higher boundary. These things should
53    # behave similar, but they are different slots.
54    kind = getKind(node.slice)
55
56    if kind == "Index":
57        return ExpressionSubscriptLookup(
58            expression=buildNode(provider, node.value, source_ref),
59            subscript=buildNode(provider, node.slice.value, source_ref),
60            source_ref=source_ref,
61        )
62    elif kind == "Slice":
63        lower = buildNode(
64            provider=provider,
65            node=node.slice.lower,
66            source_ref=source_ref,
67            allow_none=True,
68        )
69        upper = buildNode(
70            provider=provider,
71            node=node.slice.upper,
72            source_ref=source_ref,
73            allow_none=True,
74        )
75        step = buildNode(
76            provider=provider,
77            node=node.slice.step,
78            source_ref=source_ref,
79            allow_none=True,
80        )
81
82        # For Python3 there is no slicing operation, this is always done
83        # with subscript using a slice object. For Python2, it is only done
84        # if no "step" is provided.
85        use_sliceobj = step is not None or python_version >= 0x300
86
87        if use_sliceobj:
88            return ExpressionSubscriptLookup(
89                expression=buildNode(provider, node.value, source_ref),
90                subscript=makeExpressionBuiltinSlice(
91                    start=lower, stop=upper, step=step, source_ref=source_ref
92                ),
93                source_ref=source_ref,
94            )
95        else:
96            return ExpressionSliceLookup(
97                expression=buildNode(provider, node.value, source_ref),
98                lower=lower,
99                upper=upper,
100                source_ref=source_ref,
101            )
102    elif kind == "ExtSlice":
103        return ExpressionSubscriptLookup(
104            expression=buildNode(provider, node.value, source_ref),
105            subscript=buildExtSliceNode(provider, node, source_ref),
106            source_ref=source_ref,
107        )
108    elif kind == "Ellipsis":
109        return ExpressionSubscriptLookup(
110            expression=buildNode(provider, node.value, source_ref),
111            subscript=ExpressionConstantEllipsisRef(source_ref=source_ref),
112            source_ref=source_ref,
113        )
114    elif python_version >= 0x390:
115        return ExpressionSubscriptLookup(
116            expression=buildNode(provider, node.value, source_ref),
117            subscript=buildNode(provider, node.slice, source_ref),
118            source_ref=source_ref,
119        )
120    else:
121        assert False, kind
122