mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
make len(range) throw OverflowError on too big ints + impl __repr__
This commit is contained in:
@@ -81,6 +81,7 @@ fn exception_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExceptionZoo {
|
||||
pub arithmetic_error: PyObjectRef,
|
||||
pub assertion_error: PyObjectRef,
|
||||
pub attribute_error: PyObjectRef,
|
||||
pub base_exception_type: PyObjectRef,
|
||||
@@ -93,12 +94,14 @@ pub struct ExceptionZoo {
|
||||
pub name_error: PyObjectRef,
|
||||
pub not_implemented_error: PyObjectRef,
|
||||
pub os_error: PyObjectRef,
|
||||
pub overflow_error: PyObjectRef,
|
||||
pub permission_error: PyObjectRef,
|
||||
pub runtime_error: PyObjectRef,
|
||||
pub stop_iteration: PyObjectRef,
|
||||
pub syntax_error: PyObjectRef,
|
||||
pub type_error: PyObjectRef,
|
||||
pub value_error: PyObjectRef,
|
||||
pub zero_division_error: PyObjectRef,
|
||||
}
|
||||
|
||||
impl ExceptionZoo {
|
||||
@@ -113,6 +116,8 @@ impl ExceptionZoo {
|
||||
|
||||
let exception_type = create_type("Exception", &type_type, &base_exception_type, &dict_type);
|
||||
|
||||
let arithmetic_error =
|
||||
create_type("ArithmeticError", &type_type, &exception_type, &dict_type);
|
||||
let assertion_error =
|
||||
create_type("AssertionError", &type_type, &exception_type, &dict_type);
|
||||
let attribute_error =
|
||||
@@ -128,8 +133,14 @@ impl ExceptionZoo {
|
||||
let type_error = create_type("TypeError", &type_type, &exception_type, &dict_type);
|
||||
let value_error = create_type("ValueError", &type_type, &exception_type, &dict_type);
|
||||
|
||||
let overflow_error =
|
||||
create_type("OverflowError", &type_type, &arithmetic_error, &dict_type);
|
||||
let zero_division_error =
|
||||
create_type("ZeroDivisionError", &type_type, &arithmetic_error, &dict_type);
|
||||
|
||||
let module_not_found_error =
|
||||
create_type("ModuleNotFoundError", &type_type, &import_error, &dict_type);
|
||||
|
||||
let not_implemented_error = create_type(
|
||||
"NotImplementedError",
|
||||
&type_type,
|
||||
@@ -142,6 +153,7 @@ impl ExceptionZoo {
|
||||
let permission_error = create_type("PermissionError", &type_type, &os_error, &dict_type);
|
||||
|
||||
ExceptionZoo {
|
||||
arithmetic_error,
|
||||
assertion_error,
|
||||
attribute_error,
|
||||
base_exception_type,
|
||||
@@ -154,12 +166,14 @@ impl ExceptionZoo {
|
||||
name_error,
|
||||
not_implemented_error,
|
||||
os_error,
|
||||
overflow_error,
|
||||
permission_error,
|
||||
runtime_error,
|
||||
stop_iteration,
|
||||
syntax_error,
|
||||
type_error,
|
||||
value_error,
|
||||
zero_division_error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,21 @@ pub struct RangeType {
|
||||
|
||||
impl RangeType {
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
pub fn try_len(&self) -> Option<usize> {
|
||||
match self.step.sign() {
|
||||
Sign::Plus if self.start < self.end =>
|
||||
((&self.end - &self.start - 1usize) / &self.step).to_usize().unwrap() + 1,
|
||||
((&self.end - &self.start - 1usize) / &self.step).to_usize().map(|sz| sz + 1),
|
||||
Sign::Minus if self.start > self.end =>
|
||||
((&self.start - &self.end - 1usize) / (-&self.step)).to_usize().unwrap() + 1,
|
||||
_ => 0,
|
||||
((&self.start - &self.end - 1usize) / (-&self.step)).to_usize().map(|sz| sz + 1),
|
||||
_ => Some(0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.try_len().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
(self.start <= self.end && self.step.is_negative())
|
||||
@@ -51,6 +56,15 @@ impl RangeType {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn repr(&self) -> String {
|
||||
if self.step == BigInt::one() {
|
||||
format!("range({}, {})", self.start, self.end)
|
||||
} else {
|
||||
format!("range({}, {}, {})", self.start, self.end, self.step)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
@@ -63,6 +77,7 @@ pub fn init(context: &PyContext) {
|
||||
"__getitem__",
|
||||
context.new_rustfunc(range_getitem),
|
||||
);
|
||||
context.set_attr(&range_type, "__repr__", context.new_rustfunc(range_repr));
|
||||
}
|
||||
|
||||
fn range_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
@@ -121,12 +136,14 @@ fn range_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
fn range_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
|
||||
let len = match zelf.borrow().payload {
|
||||
PyObjectPayload::Range { ref range } => range.len(),
|
||||
if let Some(len) = match zelf.borrow().payload {
|
||||
PyObjectPayload::Range { ref range } => range.try_len(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(vm.ctx.new_int(len.to_bigint().unwrap()))
|
||||
} {
|
||||
Ok(vm.ctx.new_int(len.to_bigint().unwrap()))
|
||||
} else {
|
||||
Err(vm.new_overflow_error("Python int too large to convert to Rust usize".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
@@ -196,3 +213,14 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
_ => Err(vm.new_type_error("range indices must be integer or slice".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn range_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.range_type()))]);
|
||||
|
||||
let s = match zelf.borrow().payload {
|
||||
PyObjectPayload::Range { ref range } => range.repr(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(vm.ctx.new_str(s))
|
||||
}
|
||||
|
||||
@@ -105,6 +105,11 @@ impl VirtualMachine {
|
||||
self.new_exception(os_error, msg)
|
||||
}
|
||||
|
||||
pub fn new_overflow_error(&mut self, msg: String) -> PyObjectRef {
|
||||
let overflow_error = self.ctx.exceptions.overflow_error.clone();
|
||||
self.new_exception(overflow_error, msg)
|
||||
}
|
||||
|
||||
/// Create a new python ValueError object. Useful for raising errors from
|
||||
/// python functions implemented in rust.
|
||||
pub fn new_value_error(&mut self, msg: String) -> PyObjectRef {
|
||||
@@ -123,8 +128,8 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
pub fn new_not_implemented_error(&mut self, msg: String) -> PyObjectRef {
|
||||
let value_error = self.ctx.exceptions.not_implemented_error.clone();
|
||||
self.new_exception(value_error, msg)
|
||||
let not_implemented_error = self.ctx.exceptions.not_implemented_error.clone();
|
||||
self.new_exception(not_implemented_error, msg)
|
||||
}
|
||||
|
||||
pub fn new_scope(&mut self, parent_scope: Option<PyObjectRef>) -> PyObjectRef {
|
||||
|
||||
Reference in New Issue
Block a user