Skip to content

Commit 3376808

Browse files
Merge pull request RustPython#409 from skinny121/slice
Add slice type
2 parents 587617d + 7abf021 commit 3376808

File tree

11 files changed

+348
-68
lines changed

11 files changed

+348
-68
lines changed

tests/snippets/builtin_slice.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
a = []
3+
assert a[:] == []
4+
assert a[:2**100] == []
5+
assert a[-2**100:] == []
6+
assert a[::2**100] == []
7+
assert a[10:20] == []
8+
assert a[-20:-10] == []
9+
10+
b = [1, 2]
11+
12+
assert b[:] == [1, 2]
13+
assert b[:2**100] == [1, 2]
14+
assert b[-2**100:] == [1, 2]
15+
assert b[2**100:] == []
16+
assert b[::2**100] == [1]
17+
assert b[-10:1] == [1]
18+
assert b[0:0] == []
19+
assert b[1:0] == []
20+
21+
try:
22+
_ = b[::0]
23+
except ValueError:
24+
pass
25+
else:
26+
assert False, "Zero step slice should raise ValueError"
27+
28+
assert b[::-1] == [2, 1]
29+
assert b[1::-1] == [2, 1]
30+
assert b[0::-1] == [1]
31+
assert b[0:-5:-1] == [1]
32+
assert b[:0:-1] == [2]
33+
assert b[5:0:-1] == [2]
34+
35+
c = list(range(10))
36+
37+
assert c[9:6:-3] == [9]
38+
assert c[9::-3] == [9, 6, 3, 0]
39+
assert c[9::-4] == [9, 5, 1]
40+
assert c[8::-2**100] == [8]
41+
42+
assert c[7:7:-2] == []
43+
assert c[7:8:-2] == []
44+
45+
d = "123456"
46+
47+
assert d[3::-1] == "4321"
48+
assert d[4::-3] == "52"
49+
50+
51+
slice_a = slice(5)
52+
assert slice_a.start is None
53+
assert slice_a.stop == 5
54+
assert slice_a.step is None
55+
56+
slice_b = slice(1, 5)
57+
assert slice_b.start == 1
58+
assert slice_b.stop == 5
59+
assert slice_b.step is None
60+
61+
slice_c = slice(1, 5, 2)
62+
assert slice_c.start == 1
63+
assert slice_c.stop == 5
64+
assert slice_c.step == 2
65+
66+
67+
class SubScript(object):
68+
def __getitem__(self, item):
69+
assert type(item) == slice
70+
71+
def __setitem__(self, key, value):
72+
assert type(key) == slice
73+
74+
75+
ss = SubScript()
76+
_ = ss[:]
77+
ss[:1] = 1

vm/src/builtins.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
677677
ctx.set_attr(&py_mod, "repr", ctx.new_rustfunc(builtin_repr));
678678
ctx.set_attr(&py_mod, "set", ctx.set_type());
679679
ctx.set_attr(&py_mod, "setattr", ctx.new_rustfunc(builtin_setattr));
680+
ctx.set_attr(&py_mod, "slice", ctx.slice_type());
680681
ctx.set_attr(&py_mod, "staticmethod", ctx.staticmethod_type());
681682
ctx.set_attr(&py_mod, "str", ctx.str_type());
682683
ctx.set_attr(&py_mod, "sum", ctx.new_rustfunc(builtin_sum));

vm/src/frame.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use super::pyobject::{
2020
PyResult, TypeProtocol,
2121
};
2222
use super::vm::VirtualMachine;
23-
use num_traits::ToPrimitive;
23+
use num_bigint::BigInt;
2424

2525
#[derive(Clone, Debug)]
2626
enum Block {
@@ -262,22 +262,22 @@ impl Frame {
262262
assert!(*size == 2 || *size == 3);
263263
let elements = self.pop_multiple(*size);
264264

265-
let mut out: Vec<Option<i32>> = elements
265+
let mut out: Vec<Option<BigInt>> = elements
266266
.into_iter()
267267
.map(|x| match x.borrow().payload {
268-
PyObjectPayload::Integer { ref value } => Some(value.to_i32().unwrap()),
268+
PyObjectPayload::Integer { ref value } => Some(value.clone()),
269269
PyObjectPayload::None => None,
270270
_ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x),
271271
})
272272
.collect();
273273

274-
let start = out[0];
275-
let stop = out[1];
276-
let step = if out.len() == 3 { out[2] } else { None };
274+
let start = out[0].take();
275+
let stop = out[1].take();
276+
let step = if out.len() == 3 { out[2].take() } else { None };
277277

278278
let obj = PyObject::new(
279279
PyObjectPayload::Slice { start, stop, step },
280-
vm.ctx.type_type(),
280+
vm.ctx.slice_type(),
281281
);
282282
self.push_value(obj);
283283
Ok(None)

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub mod objproperty;
2222
pub mod objrange;
2323
pub mod objsequence;
2424
pub mod objset;
25+
pub mod objslice;
2526
pub mod objstr;
2627
pub mod objsuper;
2728
pub mod objtuple;

vm/src/obj/objiter.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use super::super::vm::VirtualMachine;
99
use super::objbool;
1010
// use super::objstr;
1111
use super::objtype; // Required for arg_check! to use isinstance
12-
use num_bigint::BigInt;
1312

1413
/*
1514
* This helper function is called at multiple places. First, it is called
@@ -146,7 +145,7 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
146145
}
147146

148147
PyObjectPayload::Range { ref range } => {
149-
if let Some(int) = range.get(BigInt::from(*position)) {
148+
if let Some(int) = range.get(*position) {
150149
*position += 1;
151150
Ok(vm.ctx.new_int(int))
152151
} else {

vm/src/obj/objlist.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ fn set_item(
2121
) -> PyResult {
2222
if objtype::isinstance(&idx, &vm.ctx.int_type()) {
2323
let value = objint::get_value(&idx).to_i32().unwrap();
24-
let pos_index = l.get_pos(value);
25-
l[pos_index] = obj;
26-
Ok(vm.get_none())
24+
if let Some(pos_index) = l.get_pos(value) {
25+
l[pos_index] = obj;
26+
Ok(vm.get_none())
27+
} else {
28+
Err(vm.new_index_error("list index out of range".to_string()))
29+
}
2730
} else {
2831
panic!(
2932
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",

vm/src/obj/objrange.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use super::objtype;
77
use num_bigint::{BigInt, Sign};
88
use num_integer::Integer;
99
use num_traits::{One, Signed, ToPrimitive, Zero};
10+
use std::ops::Mul;
1011

1112
#[derive(Debug, Clone)]
1213
pub struct RangeType {
@@ -77,8 +78,11 @@ impl RangeType {
7778
}
7879

7980
#[inline]
80-
pub fn get(&self, index: BigInt) -> Option<BigInt> {
81-
let result = self.start.clone() + self.step.clone() * index;
81+
pub fn get<'a, T>(&'a self, index: T) -> Option<BigInt>
82+
where
83+
&'a BigInt: Mul<T, Output = BigInt>,
84+
{
85+
let result = &self.start + &self.step * index;
8286

8387
if (self.forward() && !self.is_empty() && result < self.end)
8488
|| (!self.forward() && !self.is_empty() && result > self.end)
@@ -199,15 +203,19 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
199203

200204
match subscript.borrow().payload {
201205
PyObjectPayload::Integer { ref value } => {
202-
if let Some(int) = zrange.get(value.clone()) {
206+
if let Some(int) = zrange.get(value) {
203207
Ok(vm.ctx.new_int(int))
204208
} else {
205209
Err(vm.new_index_error("range object index out of range".to_string()))
206210
}
207211
}
208-
PyObjectPayload::Slice { start, stop, step } => {
212+
PyObjectPayload::Slice {
213+
ref start,
214+
ref stop,
215+
ref step,
216+
} => {
209217
let new_start = if let Some(int) = start {
210-
if let Some(i) = zrange.get(int.into()) {
218+
if let Some(i) = zrange.get(int) {
211219
i
212220
} else {
213221
zrange.start.clone()
@@ -217,7 +225,7 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
217225
};
218226

219227
let new_end = if let Some(int) = stop {
220-
if let Some(i) = zrange.get(int.into()) {
228+
if let Some(i) = zrange.get(int) {
221229
i
222230
} else {
223231
zrange.end
@@ -227,7 +235,7 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
227235
};
228236

229237
let new_step = if let Some(int) = step {
230-
(int as i64) * zrange.step
238+
int * zrange.step
231239
} else {
232240
zrange.step
233241
};

0 commit comments

Comments
 (0)