Add reversed builtin and range.__reversed__

This commit is contained in:
Joey Hain
2019-02-08 00:19:14 -08:00
parent a4b99253c9
commit 1ebacafb00
4 changed files with 58 additions and 0 deletions

View File

@@ -52,3 +52,7 @@ assert not range(10).__contains__(-1)
assert not range(10, 4, -2).__contains__(9)
assert not range(10, 4, -2).__contains__(4)
assert not range(10).__contains__('foo')
# __reversed__
assert list(range(5).__reversed__()) == [4, 3, 2, 1, 0]
assert list(range(5, 0, -1).__reversed__()) == [1, 2, 3, 4, 5]

View File

@@ -0,0 +1 @@
assert list(reversed(range(5))) == [4, 3, 2, 1, 0]

View File

@@ -611,6 +611,19 @@ fn builtin_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(obj, None)]);
vm.to_repr(obj)
}
fn builtin_reversed(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(obj, None)]);
match vm.get_method(obj.clone(), "__reversed__") {
Ok(value) => vm.invoke(value, PyFuncArgs::default()),
// TODO: fallback to using __len__ and __getitem__, if object supports sequence protocol
Err(..) => Err(vm.new_type_error(format!(
"'{}' object is not reversible",
objtype::get_type_name(&obj.typ()),
))),
}
}
// builtin_reversed
// builtin_round
@@ -725,6 +738,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
ctx.set_attr(&py_mod, "property", ctx.property_type());
ctx.set_attr(&py_mod, "range", ctx.range_type());
ctx.set_attr(&py_mod, "repr", ctx.new_rustfunc(builtin_repr));
ctx.set_attr(&py_mod, "reversed", ctx.new_rustfunc(builtin_reversed));
ctx.set_attr(&py_mod, "set", ctx.set_type());
ctx.set_attr(&py_mod, "setattr", ctx.new_rustfunc(builtin_setattr));
ctx.set_attr(&py_mod, "staticmethod", ctx.staticmethod_type());

View File

@@ -76,12 +76,34 @@ impl RangeType {
None
}
}
#[inline]
pub fn reversed(&self) -> Self {
match self.step.sign() {
Sign::Plus => RangeType {
start: &self.end - 1,
end: &self.start - 1,
step: -&self.step,
},
Sign::Minus => RangeType {
start: &self.end + 1,
end: &self.start + 1,
step: -&self.step,
},
Sign::NoSign => unreachable!(),
}
}
}
pub fn init(context: &PyContext) {
let ref range_type = context.range_type;
context.set_attr(&range_type, "__new__", context.new_rustfunc(range_new));
context.set_attr(&range_type, "__iter__", context.new_rustfunc(range_iter));
context.set_attr(
&range_type,
"__reversed__",
context.new_rustfunc(range_reversed),
);
context.set_attr(&range_type, "__len__", context.new_rustfunc(range_len));
context.set_attr(
&range_type,
@@ -150,6 +172,23 @@ fn range_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
))
}
fn range_reversed(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
let range = match zelf.borrow().payload {
PyObjectPayload::Range { ref range } => range.reversed(),
_ => unreachable!(),
};
Ok(PyObject::new(
PyObjectPayload::Iterator {
position: 0,
iterated_obj: PyObject::new(PyObjectPayload::Range { range }, vm.ctx.range_type()),
},
vm.ctx.iter_type(),
))
}
fn range_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);