@@ -5,25 +5,23 @@ use num_bigint::{BigInt, Sign};
5
5
use num_integer:: Integer ;
6
6
use num_traits:: { One , Signed , ToPrimitive , Zero } ;
7
7
8
- use crate :: function:: PyFuncArgs ;
8
+ use crate :: function:: { OptionalArg , PyFuncArgs } ;
9
9
use crate :: pyobject:: {
10
- PyContext , PyIteratorValue , PyObject , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
10
+ PyContext , PyIteratorValue , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol ,
11
11
} ;
12
12
use crate :: vm:: VirtualMachine ;
13
13
14
- use super :: objint:: { self , PyInt } ;
14
+ use super :: objint:: { self , PyInt , PyIntRef } ;
15
15
use super :: objslice:: PySlice ;
16
16
use super :: objtype;
17
- use crate :: obj:: objtype:: PyClassRef ;
18
-
19
- pub type PyRangeRef = PyRef < PyRange > ;
17
+ use super :: objtype:: PyClassRef ;
20
18
21
19
#[ derive( Debug , Clone ) ]
22
20
pub struct PyRange {
23
21
// Unfortunately Rust's built in range type doesn't support things like indexing
24
22
// or ranges where start > end so we need to roll our own.
25
23
pub start : BigInt ,
26
- pub end : BigInt ,
24
+ pub stop : BigInt ,
27
25
pub step : BigInt ,
28
26
}
29
27
@@ -37,11 +35,11 @@ impl PyRange {
37
35
#[ inline]
38
36
pub fn try_len ( & self ) -> Option < usize > {
39
37
match self . step . sign ( ) {
40
- Sign :: Plus if self . start < self . end => ( ( & self . end - & self . start - 1usize )
38
+ Sign :: Plus if self . start < self . stop => ( ( & self . stop - & self . start - 1usize )
41
39
/ & self . step )
42
40
. to_usize ( )
43
41
. map ( |sz| sz + 1 ) ,
44
- Sign :: Minus if self . start > self . end => ( ( & self . start - & self . end - 1usize )
42
+ Sign :: Minus if self . start > self . stop => ( ( & self . start - & self . stop - 1usize )
45
43
/ ( -& self . step ) )
46
44
. to_usize ( )
47
45
. map ( |sz| sz + 1 ) ,
@@ -57,8 +55,8 @@ impl PyRange {
57
55
#[ inline]
58
56
fn offset ( & self , value : & BigInt ) -> Option < BigInt > {
59
57
match self . step . sign ( ) {
60
- Sign :: Plus if * value >= self . start && * value < self . end => Some ( value - & self . start ) ,
61
- Sign :: Minus if * value <= self . start && * value > self . end => Some ( & self . start - value) ,
58
+ Sign :: Plus if * value >= self . start && * value < self . stop => Some ( value - & self . start ) ,
59
+ Sign :: Minus if * value <= self . start && * value > self . stop => Some ( & self . start - value) ,
62
60
_ => None ,
63
61
}
64
62
}
@@ -92,13 +90,13 @@ impl PyRange {
92
90
93
91
#[ inline]
94
92
pub fn is_empty ( & self ) -> bool {
95
- ( self . start <= self . end && self . step . is_negative ( ) )
96
- || ( self . start >= self . end && self . step . is_positive ( ) )
93
+ ( self . start <= self . stop && self . step . is_negative ( ) )
94
+ || ( self . start >= self . stop && self . step . is_positive ( ) )
97
95
}
98
96
99
97
#[ inline]
100
98
pub fn forward ( & self ) -> bool {
101
- self . start < self . end
99
+ self . start < self . stop
102
100
}
103
101
104
102
#[ inline]
@@ -108,8 +106,8 @@ impl PyRange {
108
106
{
109
107
let result = & self . start + & self . step * index;
110
108
111
- if ( self . forward ( ) && !self . is_empty ( ) && result < self . end )
112
- || ( !self . forward ( ) && !self . is_empty ( ) && result > self . end )
109
+ if ( self . forward ( ) && !self . is_empty ( ) && result < self . stop )
110
+ || ( !self . forward ( ) && !self . is_empty ( ) && result > self . stop )
113
111
{
114
112
Some ( result)
115
113
} else {
@@ -121,22 +119,22 @@ impl PyRange {
121
119
pub fn reversed ( & self ) -> Self {
122
120
// compute the last element that is actually contained within the range
123
121
// this is the new start
124
- let remainder = ( ( & self . end - & self . start ) % & self . step ) . abs ( ) ;
122
+ let remainder = ( ( & self . stop - & self . start ) % & self . step ) . abs ( ) ;
125
123
let start = if remainder. is_zero ( ) {
126
- & self . end - & self . step
124
+ & self . stop - & self . step
127
125
} else {
128
- & self . end - & remainder
126
+ & self . stop - & remainder
129
127
} ;
130
128
131
129
match self . step . sign ( ) {
132
130
Sign :: Plus => PyRange {
133
131
start,
134
- end : & self . start - 1 ,
132
+ stop : & self . start - 1 ,
135
133
step : -& self . step ,
136
134
} ,
137
135
Sign :: Minus => PyRange {
138
136
start,
139
- end : & self . start + 1 ,
137
+ stop : & self . start + 1 ,
140
138
step : -& self . step ,
141
139
} ,
142
140
Sign :: NoSign => unreachable ! ( ) ,
@@ -145,9 +143,9 @@ impl PyRange {
145
143
146
144
pub fn repr ( & self ) -> String {
147
145
if self . step == BigInt :: one ( ) {
148
- format ! ( "range({}, {})" , self . start, self . end )
146
+ format ! ( "range({}, {})" , self . start, self . stop )
149
147
} else {
150
- format ! ( "range({}, {}, {})" , self . start, self . end , self . step)
148
+ format ! ( "range({}, {}, {})" , self . start, self . stop , self . step)
151
149
}
152
150
}
153
151
}
@@ -185,40 +183,47 @@ pub fn init(context: &PyContext) {
185
183
} ) ;
186
184
}
187
185
188
- fn range_new ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
189
- arg_check ! (
190
- vm,
191
- args,
192
- required = [ ( cls, None ) , ( first, Some ( vm. ctx. int_type( ) ) ) ] ,
193
- optional = [
194
- ( second, Some ( vm. ctx. int_type( ) ) ) ,
195
- ( step, Some ( vm. ctx. int_type( ) ) )
196
- ]
197
- ) ;
186
+ type PyRangeRef = PyRef < PyRange > ;
198
187
199
- let start = if second. is_some ( ) {
200
- objint:: get_value ( first) . clone ( )
201
- } else {
202
- BigInt :: zero ( )
203
- } ;
188
+ impl PyRangeRef {
189
+ fn new ( cls : PyClassRef , stop : PyIntRef , vm : & VirtualMachine ) -> PyResult < PyRangeRef > {
190
+ PyRange {
191
+ start : Zero :: zero ( ) ,
192
+ stop : stop. value . clone ( ) ,
193
+ step : One :: one ( ) ,
194
+ }
195
+ . into_ref_with_type ( vm, cls)
196
+ }
204
197
205
- let end = if let Some ( pyint) = second {
206
- objint:: get_value ( pyint) . clone ( )
207
- } else {
208
- objint:: get_value ( first) . clone ( )
209
- } ;
198
+ fn new_from (
199
+ cls : PyClassRef ,
200
+ start : PyIntRef ,
201
+ stop : PyIntRef ,
202
+ step : OptionalArg < PyIntRef > ,
203
+ vm : & VirtualMachine ,
204
+ ) -> PyResult < PyRangeRef > {
205
+ PyRange {
206
+ start : start. value . clone ( ) ,
207
+ stop : stop. value . clone ( ) ,
208
+ step : step
209
+ . into_option ( )
210
+ . map ( |i| i. value . clone ( ) )
211
+ . unwrap_or_else ( One :: one) ,
212
+ }
213
+ . into_ref_with_type ( vm, cls)
214
+ }
215
+ }
210
216
211
- let step = if let Some ( pyint) = step {
212
- objint:: get_value ( pyint) . clone ( )
217
+ fn range_new ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
218
+ let range = if args. args . len ( ) <= 2 {
219
+ let ( cls, stop) = args. bind ( vm) ?;
220
+ PyRangeRef :: new ( cls, stop, vm)
213
221
} else {
214
- BigInt :: one ( )
215
- } ;
222
+ let ( cls, start, stop, step) = args. bind ( vm) ?;
223
+ PyRangeRef :: new_from ( cls, start, stop, step, vm)
224
+ } ?;
216
225
217
- if step. is_zero ( ) {
218
- Err ( vm. new_value_error ( "range with 0 step size" . to_string ( ) ) )
219
- } else {
220
- Ok ( PyObject :: new ( PyRange { start, end, step } , cls. clone ( ) ) )
221
- }
226
+ Ok ( range. into_object ( ) )
222
227
}
223
228
224
229
fn range_iter ( range : PyRangeRef , _vm : & VirtualMachine ) -> PyIteratorValue {
@@ -282,10 +287,10 @@ fn range_getitem(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
282
287
if let Some ( i) = range. get ( int) {
283
288
i
284
289
} else {
285
- range. end
290
+ range. stop
286
291
}
287
292
} else {
288
- range. end
293
+ range. stop
289
294
} ;
290
295
291
296
let new_step = if let Some ( int) = step {
@@ -296,7 +301,7 @@ fn range_getitem(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
296
301
297
302
Ok ( PyRange {
298
303
start : new_start,
299
- end : new_end,
304
+ stop : new_end,
300
305
step : new_step,
301
306
}
302
307
. into_ref ( vm)
@@ -384,7 +389,7 @@ fn range_start(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
384
389
385
390
fn range_stop ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
386
391
arg_check ! ( vm, args, required = [ ( zelf, Some ( vm. ctx. range_type( ) ) ) ] ) ;
387
- Ok ( vm. ctx . new_int ( get_value ( zelf) . end ) )
392
+ Ok ( vm. ctx . new_int ( get_value ( zelf) . stop ) )
388
393
}
389
394
390
395
fn range_step ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
0 commit comments