Skip to content

Commit e427daf

Browse files
HyeockJinKimcorona10
authored andcommitted
Add Slice function for range type (#83)
* Add Slice function for range type Crate a new range object by calculating start, stop, and step when slice is entered as argument to the __getitem__ function of the range Fixes #77 * Add typecall for __index__ in Index function If __index__ is defined when class is used as index value, __index__ value is used. * Add tests for range
1 parent 16d3870 commit e427daf

File tree

3 files changed

+123
-9
lines changed

3 files changed

+123
-9
lines changed

py/internal.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,21 @@ func MakeGoInt64(a Object) (int64, error) {
8787
//
8888
// Will raise TypeError if Index can't be run on this object
8989
func Index(a Object) (Int, error) {
90-
A, ok := a.(I__index__)
91-
if ok {
90+
if A, ok := a.(I__index__); ok {
9291
return A.M__index__()
9392
}
93+
94+
if A, ok, err := TypeCall0(a, "__index__"); ok {
95+
if err != nil {
96+
return 0, err
97+
}
98+
if res, ok := A.(Int); ok {
99+
return res, nil
100+
}
101+
102+
return 0, err
103+
}
104+
94105
return 0, ExceptionNewf(TypeError, "unsupported operand type(s) for index: '%s'", a.Type().Name)
95106
}
96107

py/range.go

+70-7
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ func RangeNew(metatype *Type, args Tuple, kwargs StringDict) (Object, error) {
7979
}
8080

8181
func (r *Range) M__getitem__(key Object) (Object, error) {
82+
if slice, ok := key.(*Slice); ok {
83+
return computeRangeSlice(r, slice)
84+
}
85+
8286
index, err := Index(key)
8387
if err != nil {
8488
return nil, err
8589
}
86-
// TODO(corona10): Support slice case
87-
length := computeRangeLength(r.Start, r.Stop, r.Step)
88-
if index < 0 {
89-
index += length
90-
}
90+
index = computeNegativeIndex(index, r.Length)
9191

92-
if index < 0 || index >= length {
93-
return nil, ExceptionNewf(TypeError, "range object index out of range")
92+
if index < 0 || index >= r.Length {
93+
return nil, ExceptionNewf(IndexError, "range object index out of range")
9494
}
9595
result := computeItem(r, index)
9696
return result, nil
@@ -160,6 +160,69 @@ func computeRangeLength(start, stop, step Int) Int {
160160
return res
161161
}
162162

163+
func computeNegativeIndex(index, length Int) Int {
164+
if index < 0 {
165+
index += length
166+
}
167+
return index
168+
}
169+
170+
func computeBoundIndex(index, length Int) Int {
171+
if index < 0 {
172+
index = 0
173+
} else if index > length {
174+
index = length
175+
}
176+
return index
177+
}
178+
179+
func computeRangeSlice(r *Range, s *Slice) (Object, error) {
180+
start, err := Index(s.Start)
181+
if err != nil {
182+
start = 0
183+
}
184+
stop, err := Index(s.Stop)
185+
if err != nil {
186+
stop = r.Length
187+
}
188+
189+
step, err := Index(s.Step)
190+
if err != nil {
191+
step = 1
192+
}
193+
if step == 0 {
194+
return nil, ExceptionNewf(ValueError, "slice step cannot be zero")
195+
}
196+
start = computeNegativeIndex(start, r.Length)
197+
stop = computeNegativeIndex(stop, r.Length)
198+
199+
start = computeBoundIndex(start, r.Length)
200+
stop = computeBoundIndex(stop, r.Length)
201+
202+
startIndex := computeItem(r, start)
203+
stopIndex := computeItem(r, stop)
204+
stepIndex := step * r.Step
205+
206+
var sliceLength Int
207+
if start < stop {
208+
if stepIndex < 0 {
209+
startIndex, stopIndex = stopIndex-1, startIndex-1
210+
}
211+
} else {
212+
if stepIndex < 0 {
213+
startIndex, stopIndex = stopIndex+1, startIndex+1
214+
}
215+
}
216+
sliceLength = computeRangeLength(startIndex, stopIndex, stepIndex)
217+
218+
return &Range{
219+
Start: startIndex,
220+
Stop: stopIndex,
221+
Step: stepIndex,
222+
Length: sliceLength,
223+
}, nil
224+
}
225+
163226
// Check interface is satisfied
164227
var _ I__getitem__ = (*Range)(nil)
165228
var _ I__iter__ = (*Range)(nil)

py/tests/range.py

+40
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,44 @@
7676
assert str(range(0, 3)) == 'range(0, 3)'
7777
assert str(range(10, 3, -2)) == 'range(10, 3, -2)'
7878

79+
doc="range_slice"
80+
a = range(10)
81+
assert a[::-1][0] == 9
82+
assert a[::-1][9] == 0
83+
assert a[0:3][0] == 0
84+
assert a[0:3][2] == 2
85+
assert a[-3:10][0] == 7
86+
assert a[-100:13][0] == 0
87+
assert a[-100:13][9] == 9
88+
89+
try:
90+
a[0:3][3]
91+
except IndexError:
92+
pass
93+
else:
94+
assert False, "IndexError not raised"
95+
try:
96+
a[100:13][0]
97+
except IndexError:
98+
pass
99+
else:
100+
assert False, "IndexError not raised"
101+
try:
102+
a[0:3:0]
103+
except ValueError:
104+
pass
105+
else:
106+
assert False, "ValueError not raised"
107+
108+
doc="range_index"
109+
class Index:
110+
def __index__(self):
111+
return 1
112+
113+
a = range(10)
114+
b = Index()
115+
assert a[b] == 1
116+
assert a[b:10] == a[1:10]
117+
assert a[10:b:-1] == a[10:1:-1]
118+
79119
doc="finished"

0 commit comments

Comments
 (0)