#     Copyright 2016, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.
#
""" Reformulation of subscript into slicing.

For Python2, there is a difference between x[a], x[a:b], x[a:b:c] whereas
Python3 treats the later by making a slice object, Python2 tries to have
special slice access, if available, or building a slice object only at the
end.

Consult the developer manual for information. TODO: Add ability to sync
source code comments with developer manual sections.
"""

from nuitka.nodes.ConstantRefNodes import ExpressionConstantEllipsisRef
from nuitka.nodes.SliceNodes import (
    ExpressionBuiltinSlice,
    ExpressionSliceLookup
)
from nuitka.nodes.SubscriptNodes import ExpressionSubscriptLookup
from nuitka.PythonVersions import python_version

from .Helpers import buildNode, getKind
from .ReformulationAssignmentStatements import buildExtSliceNode


def buildSubscriptNode(provider, node, source_ref):
    # Subscript expression nodes.

    assert getKind(node.ctx) == "Load", source_ref

    # The subscript "[]" operator is one of many different things. This is
    # expressed by this kind, there are "slice" lookups (two values, even if one
    # is using default), and then "index" lookups. The form with three argument
    # is really an "index" lookup, with a slice object. And the "..." lookup is
    # also an index loop-up, with it as the argument. So this splits things into
    # two different operations, "subscript" with a single "subscript" object. Or
    # a slice lookup with a lower and higher boundary. These things should
    # behave similar, but they are different slots.
    kind = getKind(node.slice)

    if kind == "Index":
        return ExpressionSubscriptLookup(
            subscribed = buildNode(provider, node.value, source_ref),
            subscript  = buildNode(provider, node.slice.value, source_ref),
            source_ref = source_ref
        )
    elif kind == "Slice":
        lower = buildNode(
            provider   = provider,
            node       = node.slice.lower,
            source_ref = source_ref,
            allow_none = True
        )
        upper = buildNode(
            provider   = provider,
            node       = node.slice.upper,
            source_ref = source_ref,
            allow_none = True
        )
        step = buildNode(
            provider   = provider,
            node       = node.slice.step,
            source_ref = source_ref,
            allow_none = True
        )


        # For Python3 there is no slicing operation, this is always done
        # with subscript using a slice object. For Python2, it is only done
        # if no "step" is provided.
        use_sliceobj = step is not None or python_version >= 300

        if use_sliceobj:
            return ExpressionSubscriptLookup(
                subscribed = buildNode(provider, node.value, source_ref),
                subscript  = ExpressionBuiltinSlice(
                    start      = lower,
                    stop       = upper,
                    step       = step,
                    source_ref = source_ref
                ),
                source_ref = source_ref
            )
        else:
            return ExpressionSliceLookup(
                expression = buildNode(provider, node.value, source_ref),
                lower      = lower,
                upper      = upper,
                source_ref = source_ref
            )
    elif kind == "ExtSlice":
        return ExpressionSubscriptLookup(
            subscribed = buildNode(provider, node.value, source_ref),
            subscript  = buildExtSliceNode(provider, node, source_ref),
            source_ref = source_ref
        )
    elif kind == "Ellipsis":
        return ExpressionSubscriptLookup(
            subscribed = buildNode(provider, node.value, source_ref),
            subscript  = ExpressionConstantEllipsisRef(
                source_ref = source_ref
            ),
            source_ref = source_ref
        )
    else:
        assert False, kind
