Skip to content

Commit de98ac6

Browse files
Merge pull request #442 from OddCoincidence/float-parsing
Support float(<str>) and float(<bytes>)
2 parents 17bde53 + 38c0ea0 commit de98ac6

File tree

5 files changed

+115
-5
lines changed

5 files changed

+115
-5
lines changed

Cargo.lock

Lines changed: 41 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/snippets/floats.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
import math
2+
3+
def assert_raises(expr, exc_type):
4+
"""
5+
Helper function to assert `expr` raises an exception of type `exc_type`
6+
Args:
7+
expr: Callable
8+
exec_type: Exception
9+
Returns:
10+
None
11+
Raises:
12+
Assertion error on failure
13+
"""
14+
try:
15+
expr(None)
16+
except exc_type:
17+
assert True
18+
else:
19+
assert False
20+
121
1 + 1.1
222

323
a = 1.2
@@ -39,3 +59,25 @@
3959
assert a >= 'a'
4060
except TypeError:
4161
pass
62+
63+
assert math.isnan(float('nan'))
64+
assert math.isnan(float('NaN'))
65+
assert math.isnan(float('+NaN'))
66+
assert math.isnan(float('-NaN'))
67+
68+
assert math.isinf(float('inf'))
69+
assert math.isinf(float('Inf'))
70+
assert math.isinf(float('+Inf'))
71+
assert math.isinf(float('-Inf'))
72+
73+
assert float('+Inf') > 0
74+
assert float('-Inf') < 0
75+
76+
assert float('3.14') == 3.14
77+
assert float('2.99e-23') == 2.99e-23
78+
79+
assert float(b'3.14') == 3.14
80+
assert float(b'2.99e-23') == 2.99e-23
81+
82+
assert_raises(lambda _: float('foo'), ValueError)
83+
assert_raises(lambda _: float(2**10000), OverflowError)

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ statrs = "0.10.0"
2121
caseless = "0.2.1"
2222
unicode-segmentation = "1.2.1"
2323
lazy_static = "^1.0.1"
24+
lexical = "2.0.0"

vm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
extern crate bitflags;
1010
#[macro_use]
1111
extern crate lazy_static;
12+
extern crate lexical;
1213
#[macro_use]
1314
extern crate log;
1415
// extern crate env_logger;

vm/src/obj/objfloat.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use super::super::pyobject::{
22
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
33
};
44
use super::super::vm::VirtualMachine;
5+
use super::objbytes;
56
use super::objint;
7+
use super::objstr;
68
use super::objtype;
79
use num_bigint::ToBigInt;
810
use num_traits::ToPrimitive;
@@ -23,9 +25,35 @@ fn float_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2325
let val = if objtype::isinstance(arg, &vm.ctx.float_type()) {
2426
get_value(arg)
2527
} else if objtype::isinstance(arg, &vm.ctx.int_type()) {
26-
objint::get_value(arg).to_f64().unwrap()
28+
match objint::get_value(arg).to_f64() {
29+
Some(f) => f,
30+
None => {
31+
return Err(vm.new_overflow_error("int too large to convert to float".to_string()));
32+
}
33+
}
34+
} else if objtype::isinstance(arg, &vm.ctx.str_type()) {
35+
match lexical::try_parse(objstr::get_value(arg)) {
36+
Ok(f) => f,
37+
Err(_) => {
38+
let arg_repr = vm.to_pystr(arg)?;
39+
return Err(
40+
vm.new_value_error(format!("could not convert string to float: {}", arg_repr))
41+
);
42+
}
43+
}
44+
} else if objtype::isinstance(arg, &vm.ctx.bytes_type()) {
45+
match lexical::try_parse(objbytes::get_value(arg).as_slice()) {
46+
Ok(f) => f,
47+
Err(_) => {
48+
let arg_repr = vm.to_pystr(arg)?;
49+
return Err(
50+
vm.new_value_error(format!("could not convert string to float: {}", arg_repr))
51+
);
52+
}
53+
}
2754
} else {
28-
return Err(vm.new_type_error("Cannot construct int".to_string()));
55+
let type_name = objtype::get_type_name(&arg.typ());
56+
return Err(vm.new_type_error(format!("can't convert {} to float", type_name)));
2957
};
3058
set_value(zelf, val);
3159
Ok(vm.get_none())

0 commit comments

Comments
 (0)