From 4400e3d849222206a744ba47e321ca6ef003deb8 Mon Sep 17 00:00:00 2001 From: Philip Kaelbling <60230598+pakaelbling@users.noreply.github.com> Date: Sun, 25 Feb 2024 11:42:31 -0500 Subject: [PATCH] Generic Slices (#544) * Changed slice fields to generics, added check to adjust_indices * fix typecheck * Refactored Slice class, fixed test * fix test * made slice fields optional, updated tests * Fix list optimization for new slices; update tests --------- Co-authored-by: A. R. Shajii --- codon/cir/transform/pythonic/list.cpp | 2 +- stdlib/internal/types/slice.codon | 36 ++++++++++++++++++++++++--- test/core/containers.codon | 34 +++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/codon/cir/transform/pythonic/list.cpp b/codon/cir/transform/pythonic/list.cpp index 38c785dc..aee57a2e 100644 --- a/codon/cir/transform/pythonic/list.cpp +++ b/codon/cir/transform/pythonic/list.cpp @@ -14,7 +14,7 @@ namespace pythonic { namespace { static const std::string LIST = "std.internal.types.ptr.List"; -static const std::string SLICE = "std.internal.types.slice.Slice"; +static const std::string SLICE = "std.internal.types.slice.Slice[int,int,int]"; bool isList(Value *v) { return v->getType()->getName().rfind(LIST + "[", 0) == 0; } bool isSlice(Value *v) { return v->getType()->getName() == SLICE; } diff --git a/stdlib/internal/types/slice.codon b/stdlib/internal/types/slice.codon index 06cb4d7a..8c0affbd 100644 --- a/stdlib/internal/types/slice.codon +++ b/stdlib/internal/types/slice.codon @@ -2,14 +2,36 @@ @tuple class Slice: - start: Optional[int] - stop: Optional[int] - step: Optional[int] + start: Optional[T] + stop: Optional[U] + step: Optional[V] + T: type + U: type + V: type - def __new__(stop: Optional[int]): + def __new__(stop: Optional[U], U: type = int): return Slice(None, stop, None) + def __new__( + start: Optional[T], + stop: Optional[U], + T: type = int, + U: type = int): + return Slice(start, stop, None) + + def __new__( + start: Optional[T], + stop: Optional[U], + step: Optional[V], + T: type = int, + U: type = int, + V: type = int) -> Slice[T, U, V]: + return (start, stop, step) + def adjust_indices(self, length: int) -> Tuple[int, int, int, int]: + if not (T is int and U is int and V is int): + compile_error("slice indices must be integers or None") + step: int = self.step if self.step is not None else 1 start: int = 0 stop: int = 0 @@ -58,4 +80,10 @@ class Slice: def __repr__(self): return f"slice({self.start}, {self.stop}, {self.step})" + def __eq__(self, other: Slice): + return self.start == other.start and self.step == other.step and self.stop == other.stop + + def __ne__(self, other: Slice): + return not self.__eq__(other) + slice = Slice diff --git a/test/core/containers.codon b/test/core/containers.codon index 4163f44a..f85d1177 100644 --- a/test/core/containers.codon +++ b/test/core/containers.codon @@ -764,6 +764,40 @@ def test_slice(): x = X(tmp) x[1:2] = 42 assert tmp == [(slice(1, 2), 42)] + + # Non-int elements + def check_types(s, T: type, U: type, V: type): + return (type(s.start) is Optional[T] and + type(s.stop) is Optional[U] and + type(s.step) is Optional[V]) + assert check_types(slice(1j, 'x', 3.14), complex, str, float) + assert check_types(slice(None, 'x', 3.14), int, str, float) + assert check_types(slice(1j, None, 3.14), complex, int, float) + assert check_types(slice(1j, 'x', None), complex, str, int) + assert check_types(slice(1j, None, None), complex, int, int) + assert check_types(slice(None, 'x', None), int, str, int) + assert check_types(slice(None, None, 3.14), int, int, float) + assert check_types(slice(None, None, None), int, int, int) + assert check_types(slice(1j, 'x'), complex, str, int) + assert check_types(slice(None, 'x'), int, str, int) + assert check_types(slice(1j, None), complex, int, int) + assert check_types(slice(None, None), int, int, int) + assert check_types(slice(1j), int, complex, int) + assert check_types(slice(None), int, int, int) + + # eq / ne + assert slice(1, 2, 3) == slice(1, 2, 3) + assert slice(0, 2, 3) != slice(1, 2, 3) + assert slice(1, 0, 3) != slice(1, 2, 3) + assert slice(1, 2, 0) != slice(1, 2, 3) + assert slice(None, None, None) == slice(None, None, None) + assert slice(None, 42, None) == slice(None, 42, None) + assert slice(None, 42, None) != slice(None, 43, None) + assert slice(1, None, 3) == slice(1, None, 3) + assert slice(1, None, 3) != slice(1, None, 0) + assert slice(1, None, 3) != slice(0, None, 3) + assert slice(1) == slice(1) + assert slice(1) != slice(2) test_slice() @test