Support reversed on sequence

This commit is contained in:
Aviv Palivoda committed 2019-06-14 15:25:24 +03:00
1 parent 8b894a11fb
commit 60e799727f
4 files changed
+38 -17

No files matched your search

+3
View File
@@ -1 +1,4 @@
assert list(reversed(range(5))) == [4, 3, 2, 1, 0]
l = [5,4,3,2,1]
assert list(reversed(l)) == [1,2,3,4,5]
+16 -6
View File
@@ -2,12 +2,13 @@
//!
//! Implements functions listed here: https://docs.python.org/3/library/builtins.html
use std::cell::Cell;
use std::char;
use std::io::{self, Write};
use std::str;
use num_bigint::Sign;
use num_traits::{Signed, Zero};
use num_traits::{Signed, ToPrimitive, Zero};
use crate::compile;
use crate::obj::objbool;
@@ -684,11 +685,20 @@ fn builtin_repr(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStringRef>
fn builtin_reversed(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(obj, None)]);
// TODO: fallback to using __len__ and __getitem__, if object supports sequence protocol
let method = vm.get_method_or_type_error(obj.clone(), "__reversed__", || {
format!("argument to reversed() must be a sequence")
})?;
vm.invoke(method, PyFuncArgs::default())
if let Some(reversed_method) = vm.get_method(obj.clone(), "__reversed__") {
vm.invoke(reversed_method?, PyFuncArgs::default())
} else {
vm.get_method_or_type_error(obj.clone(), "__getitem__", || {
format!("argument to reversed() must be a sequence")
})?;
let len = vm.call_method(&obj.clone(), "__len__", PyFuncArgs::default())?;
let obj_iterator = objiter::PySequenceIterator {
position: Cell::new(objint::get_value(&len).to_isize().unwrap() - 1),
obj: obj.clone(),
reversed: true,
};
Ok(obj_iterator.into_ref(vm).into_object())
}
}
fn builtin_round(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
+18 -11
View File
@@ -28,6 +28,7 @@ pub fn get_iter(vm: &VirtualMachine, iter_target: &PyObjectRef) -> PyResult {
let obj_iterator = PySequenceIterator {
position: Cell::new(0),
obj: iter_target.clone(),
reversed: false,
};
Ok(obj_iterator.into_ref(vm).into_object())
}
@@ -80,8 +81,9 @@ pub fn new_stop_iteration(vm: &VirtualMachine) -> PyObjectRef {
#[pyclass]
#[derive(Debug)]
pub struct PySequenceIterator {
pub position: Cell<usize>,
pub position: Cell<isize>,
pub obj: PyObjectRef,
pub reversed: bool,
}
impl PyValue for PySequenceIterator {
@@ -94,17 +96,22 @@ impl PyValue for PySequenceIterator {
impl PySequenceIterator {
#[pymethod(name = "__next__")]
fn next(&self, vm: &VirtualMachine) -> PyResult {
let number = vm.ctx.new_int(self.position.get());
match vm.call_method(&self.obj, "__getitem__", vec![number]) {
Ok(val) => {
self.position.set(self.position.get() + 1);
Ok(val)
if self.position.get() >= 0 {
let step: isize = if self.reversed { -1 } else { 1 };
let number = vm.ctx.new_int(self.position.get());
match vm.call_method(&self.obj, "__getitem__", vec![number]) {
Ok(val) => {
self.position.set(self.position.get() + step);
Ok(val)
}
Err(ref e) if objtype::isinstance(&e, &vm.ctx.exceptions.index_error) => {
Err(new_stop_iteration(vm))
}
// also catches stop_iteration => stop_iteration
Err(e) => Err(e),
}
Err(ref e) if objtype::isinstance(&e, &vm.ctx.exceptions.index_error) => {
Err(new_stop_iteration(vm))
}
// also catches stop_iteration => stop_iteration
Err(e) => Err(e),
} else {
Err(new_stop_iteration(vm))
}
}
+1
View File
@@ -1149,6 +1149,7 @@ where
objiter::PySequenceIterator {
position: Cell::new(0),
obj: obj.clone(),
reversed: false,
}
.into_ref(vm)
.into_object(),