Implement objcomplex::parse_str() to replace Complex64::from_str()

This commit is contained in:
Youngchan Lee authored and GitHub committed 2020-08-18 02:19:58 +09:00
1 parent d4a35b9a92
commit ec5d168de2
2 files changed
+86 -4

No files matched your search

+45
View File
@@ -164,3 +164,48 @@ assert complex("5-2j") == 5 - 2j
assert complex("-2j") == -2j
assert_raises(TypeError, lambda: complex("5+2j", 1))
assert_raises(ValueError, lambda: complex("abc"))
assert complex("1+10j") == 1+10j
assert complex(10) == 10+0j
assert complex(10.0) == 10+0j
assert complex(10) == 10+0j
assert complex(10+0j) == 10+0j
assert complex(1, 10) == 1+10j
assert complex(1, 10) == 1+10j
assert complex(1, 10.0) == 1+10j
assert complex(1, 10) == 1+10j
assert complex(1, 10) == 1+10j
assert complex(1, 10.0) == 1+10j
assert complex(1.0, 10) == 1+10j
assert complex(1.0, 10) == 1+10j
assert complex(1.0, 10.0) == 1+10j
assert complex(3.14+0j) == 3.14+0j
assert complex(3.14) == 3.14+0j
assert complex(314) == 314.0+0j
assert complex(314) == 314.0+0j
assert complex(3.14+0j, 0j) == 3.14+0j
assert complex(3.14, 0.0) == 3.14+0j
assert complex(314, 0) == 314.0+0j
assert complex(314, 0) == 314.0+0j
assert complex(0j, 3.14j) == -3.14+0j
assert complex(0.0, 3.14j) == -3.14+0j
assert complex(0j, 3.14) == 3.14j
assert complex(0.0, 3.14) == 3.14j
assert complex("1") == 1+0j
assert complex("1j") == 1j
assert complex() == 0
assert complex("-1") == -1
assert complex("+1") == +1
assert complex("(1+2j)") == 1+2j
assert complex("(1.3+2.2j)") == 1.3+2.2j
assert complex("3.14+1J") == 3.14+1j
assert complex(" ( +3.14-6J )") == 3.14-6j
assert complex(" ( +3.14-J )") == 3.14-1j
assert complex(" ( +3.14+j )") == 3.14+1j
assert complex("J") == 1j
assert complex("( j )") == 1j
assert complex("+J") == 1j
assert complex("( -j)") == -1j
assert complex('1e-500') == 0.0 + 0.0j
assert complex('-1e-500j') == 0.0 - 0.0j
assert complex('-1e-500+1e-500j') == -0.0 + 0.0j
+41 -4
View File
@@ -1,6 +1,5 @@
use num_complex::Complex64;
use num_traits::Zero;
use std::str::FromStr;
use super::objfloat;
use super::objstr::PyString;
@@ -10,7 +9,7 @@ use crate::pyobject::{
PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::vm::VirtualMachine;
use rustpython_common::hash;
use rustpython_common::{float_ops, hash};
/// Create a complex number from a real part and an optional imaginary part.
///
@@ -254,8 +253,9 @@ impl PyComplex {
"complex() can't take second arg if first is a string".to_owned(),
));
}
let value = Complex64::from_str(s.borrow_value())
.map_err(|err| vm.new_value_error(err.to_string()))?;
let value = parse_str(s.borrow_value().trim()).ok_or_else(|| {
vm.new_value_error("complex() arg is a malformed string".to_owned())
})?;
return Self::from(value).into_ref_with_type(vm, cls);
} else {
return Err(vm.new_type_error(format!(
@@ -308,3 +308,40 @@ struct ComplexArgs {
#[pyarg(positional_or_keyword, default = "None")]
imag: Option<PyObjectRef>,
}
fn parse_str(s: &str) -> Option<Complex64> {
// Handle parentheses
let s = match s.strip_prefix('(') {
None => s,
Some(s) => match s.strip_suffix(')') {
None => return None,
Some(s) => s.trim(),
},
};
let value = match s.strip_suffix(|c| c == 'j' || c == 'J') {
None => Complex64::new(float_ops::parse_str(s)?, 0.0),
Some(mut s) => {
let mut real = 0.0;
// Find the central +/- operator. If it exists, parse the real part.
for (i, w) in s.as_bytes().windows(2).enumerate() {
if (w[1] == b'+' || w[1] == b'-') && !(w[0] == b'e' || w[0] == b'E') {
real = float_ops::parse_str(&s[..=i])?;
s = &s[i + 1..];
break;
}
}
let imag = match s {
// "j", "+j"
"" | "+" => 1.0,
// "-j"
"-" => -1.0,
s => float_ops::parse_str(s)?,
};
Complex64::new(real, imag)
}
};
Some(value)
}