Merge pull request #1567 from HyeockJinKim/issue1527

Modify str to float
This commit is contained in:
Noah
2019-10-26 15:45:44 -05:00
committed by GitHub
2 changed files with 51 additions and 14 deletions

View File

@@ -304,3 +304,15 @@ assert float(1e-5).__repr__() == "1e-05"
assert float(1e-4).__repr__() == "0.0001"
assert float(1.2345678901234567890).__repr__() == "1.2345678901234567"
assert float(1.2345678901234567890e308).__repr__() == "1.2345678901234567e+308"
assert float('0_0') == 0.0
assert float('.0') == 0.0
assert float('0.') == 0.0
assert_raises(ValueError, lambda: float('0._0'))
assert_raises(ValueError, lambda: float('0_.0'))
assert_raises(ValueError, lambda: float('._0'))
assert_raises(ValueError, lambda: float('0_'))
assert_raises(ValueError, lambda: float('0._'))
assert_raises(ValueError, lambda: float('_.0'))
assert_raises(ValueError, lambda: float('._0'))

View File

@@ -597,31 +597,56 @@ impl PyFloat {
}
}
fn str_to_float(vm: &VirtualMachine, literal: &str) -> PyResult<f64> {
if literal.starts_with('_') || literal.ends_with('_') {
return Err(invalid_convert(vm, literal));
}
let mut buf = String::with_capacity(literal.len());
let mut last_tok: Option<char> = None;
for c in literal.chars() {
if !(c.is_ascii_alphanumeric() || c == '_' || c == '+' || c == '-' || c == '.') {
return Err(invalid_convert(vm, literal));
}
if !c.is_ascii_alphanumeric() {
if let Some(l) = last_tok {
if !l.is_ascii_alphanumeric() {
return Err(invalid_convert(vm, literal));
}
}
}
if c != '_' {
buf.push(c);
}
last_tok = Some(c);
}
if let Ok(f) = lexical::parse(buf.as_str()) {
Ok(f)
} else {
Err(invalid_convert(vm, literal))
}
}
fn invalid_convert(vm: &VirtualMachine, literal: &str) -> PyObjectRef {
vm.new_value_error(format!("could not convert string to float: '{}'", literal))
}
fn to_float(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<f64> {
let value = if objtype::isinstance(&obj, &vm.ctx.float_type()) {
get_value(&obj)
} else if objtype::isinstance(&obj, &vm.ctx.int_type()) {
objint::get_float_value(&obj, vm)?
} else if objtype::isinstance(&obj, &vm.ctx.str_type()) {
match lexical::parse(objstr::get_value(&obj).trim()) {
Ok(f) => f,
Err(_) => {
let arg_repr = vm.to_pystr(obj)?;
return Err(vm.new_value_error(format!(
"could not convert string to float: '{}'",
arg_repr
)));
}
}
str_to_float(vm, objstr::get_value(&obj).trim())?
} else if objtype::isinstance(&obj, &vm.ctx.bytes_type()) {
match lexical::parse(objbytes::get_value(&obj).as_slice()) {
Ok(f) => f,
Err(_) => {
let arg_repr = vm.to_pystr(obj)?;
return Err(vm.new_value_error(format!(
"could not convert string to float: '{}'",
arg_repr
)));
return Err(invalid_convert(vm, arg_repr.as_str()));
}
}
} else {