non-int indexable base for int()

This commit is contained in:
Jeong YunWon
2020-02-28 03:39:49 +09:00
parent f21e35c31a
commit 4be3a365ce
4 changed files with 42 additions and 24 deletions

View File

@@ -280,7 +280,6 @@ class IntTestCases(unittest.TestCase):
with self.assertRaises(TypeError):
int('0', 5.0)
@unittest.skip("TODO: RUSTPYTHON")
def test_int_base_indexable(self):
class MyIndexable(object):
def __init__(self, value):

View File

@@ -659,12 +659,13 @@ struct IntOptions {
#[pyarg(positional_only, optional = true)]
val_options: OptionalArg<PyObjectRef>,
#[pyarg(positional_or_keyword, optional = true)]
base: OptionalArg<PyIntRef>,
base: OptionalArg<PyObjectRef>,
}
impl IntOptions {
fn get_int_value(self, vm: &VirtualMachine) -> PyResult<BigInt> {
if let OptionalArg::Present(val) = self.val_options {
// FIXME: unnessessary bigint clone/creation
let base = if let OptionalArg::Present(base) = self.base {
if !(objtype::isinstance(&val, &vm.ctx.str_type())
|| objtype::isinstance(&val, &vm.ctx.bytes_type()))
@@ -673,11 +674,17 @@ impl IntOptions {
"int() can't convert non-string with explicit base".to_owned(),
));
}
base
let base = vm.to_index(&base).unwrap_or_else(|| {
Err(vm.new_type_error(format!(
"'{}' object cannot be interpreted as an integer missing string argument",
base.class().name
)))
})?;
base.as_bigint().clone()
} else {
PyInt::new(10).into_ref(vm)
BigInt::from(10)
};
to_int(vm, &val, base.as_bigint())
to_int(vm, &val, &base)
} else if let OptionalArg::Present(_) = self.base {
Err(vm.new_type_error("int() missing string argument".to_owned()))
} else {

View File

@@ -3,7 +3,6 @@ use super::objtype::PyClassRef;
use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyobject::{
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryIntoRef,
TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_bigint::{BigInt, ToBigInt};
@@ -323,23 +322,12 @@ fn to_index_value(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Option<Big
return Ok(None);
}
if let Some(val) = obj.payload::<PyInt>() {
Ok(Some(val.as_bigint().clone()))
} else {
let cls = obj.class();
if cls.has_attr("__index__") {
let index_result = vm.call_method(obj, "__index__", vec![])?;
if let Some(val) = index_result.payload::<PyInt>() {
Ok(Some(val.as_bigint().clone()))
} else {
Err(vm.new_type_error("__index__ method returned non integer".to_owned()))
}
} else {
Err(vm.new_type_error(
"slice indices must be integers or None or have an __index__ method".to_owned(),
))
}
}
let result = vm.to_index(obj).unwrap_or_else(|| {
Err(vm.new_type_error(
"slice indices must be integers or None or have an __index__ method".to_owned(),
))
})?;
Ok(Some(result.as_bigint().clone()))
}
pub fn init(context: &PyContext) {

View File

@@ -29,7 +29,7 @@ use crate::import;
use crate::obj::objbool;
use crate::obj::objcode::{PyCode, PyCodeRef};
use crate::obj::objdict::PyDictRef;
use crate::obj::objint::PyInt;
use crate::obj::objint::{PyInt, PyIntRef};
use crate::obj::objiter;
use crate::obj::objlist::PyList;
use crate::obj::objmodule::{self, PyModule};
@@ -546,6 +546,30 @@ impl VirtualMachine {
Ok(self.new_str(ascii))
}
pub fn to_index(&self, obj: &PyObjectRef) -> Option<PyResult<PyIntRef>> {
Some(
if let Ok(val) = TryFromObject::try_from_object(self, obj.clone()) {
Ok(val)
} else {
let cls = obj.class();
if cls.has_attr("__index__") {
self.call_method(obj, "__index__", vec![]).and_then(|r| {
if let Ok(val) = TryFromObject::try_from_object(self, r) {
Ok(val)
} else {
Err(self.new_type_error(format!(
"__index__ returned non-int (type {})",
cls.name
)))
}
})
} else {
return None;
}
},
)
}
pub fn import(&self, module: &str, from_list: &[String], level: usize) -> PyResult {
// if the import inputs seem weird, e.g a package import or something, rather than just
// a straight `import ident`