@@ -79,18 +79,18 @@ func RangeNew(metatype *Type, args Tuple, kwargs StringDict) (Object, error) {
79
79
}
80
80
81
81
func (r * Range ) M__getitem__ (key Object ) (Object , error ) {
82
+ if slice , ok := key .(* Slice ); ok {
83
+ return computeRangeSlice (r , slice )
84
+ }
85
+
82
86
index , err := Index (key )
83
87
if err != nil {
84
88
return nil , err
85
89
}
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 )
91
91
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" )
94
94
}
95
95
result := computeItem (r , index )
96
96
return result , nil
@@ -160,6 +160,69 @@ func computeRangeLength(start, stop, step Int) Int {
160
160
return res
161
161
}
162
162
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
+
163
226
// Check interface is satisfied
164
227
var _ I__getitem__ = (* Range )(nil )
165
228
var _ I__iter__ = (* Range )(nil )
0 commit comments