From 38c0ea06e53e49412d7e8e356b879321ee305923 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Mon, 11 Feb 2019 19:39:48 -0800 Subject: [PATCH] Support float() and float() --- Cargo.lock | 44 +++++++++++++++++++++++++++++++++++++--- tests/snippets/floats.py | 42 ++++++++++++++++++++++++++++++++++++++ vm/Cargo.toml | 1 + vm/src/lib.rs | 1 + vm/src/obj/objfloat.rs | 32 +++++++++++++++++++++++++++-- 5 files changed, 115 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec5a35a009..9f5ffa3972 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -402,6 +402,26 @@ name = "lazy_static" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lexical" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lexical-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lexical-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" version = "0.2.42" @@ -709,6 +729,7 @@ dependencies = [ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "caseless 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lexical 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -754,7 +775,7 @@ dependencies = [ [[package]] name = "ryu" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -783,7 +804,7 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -808,6 +829,19 @@ name = "sourcefile" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stackvector" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "static_assertions" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "statrs" version = "0.10.0" @@ -1188,6 +1222,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lalrpop-snap 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "60013fd6be14317d43f47658b1440956a9ca48a9ed0257e0e0a59aac13e43a1f" "checksum lalrpop-util 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "60c6c48ba857cd700673ce88907cadcdd7e2cd7783ed02378537c5ffd4f6460c" "checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" +"checksum lexical 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4fac65df7e751b57bb3a334c346239cb4ce2601907d698726ceeb82a54ba4ef" +"checksum lexical-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "025babf624c0c2b4bed1373efd684d5d0b2eecd61138d26ec3eec77bf0f2e33d" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac" @@ -1224,7 +1260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rustyline 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6010155119d53aac4f5b987cb8f6ea913d0d64d9b237da36f8f96a90cb3f5385" -"checksum ryu 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c066b8e2923f05d4718a06d2622f189ff362bc642bfade6c6629f0440f3827" +"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" "checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" @@ -1232,6 +1268,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" +"checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6" +"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum statrs 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" diff --git a/tests/snippets/floats.py b/tests/snippets/floats.py index 6c00b9f4c5..8ca26f0ae8 100644 --- a/tests/snippets/floats.py +++ b/tests/snippets/floats.py @@ -1,3 +1,23 @@ +import math + +def assert_raises(expr, exc_type): + """ + Helper function to assert `expr` raises an exception of type `exc_type` + Args: + expr: Callable + exec_type: Exception + Returns: + None + Raises: + Assertion error on failure + """ + try: + expr(None) + except exc_type: + assert True + else: + assert False + 1 + 1.1 a = 1.2 @@ -39,3 +59,25 @@ assert a >= 'a' except TypeError: pass + +assert math.isnan(float('nan')) +assert math.isnan(float('NaN')) +assert math.isnan(float('+NaN')) +assert math.isnan(float('-NaN')) + +assert math.isinf(float('inf')) +assert math.isinf(float('Inf')) +assert math.isinf(float('+Inf')) +assert math.isinf(float('-Inf')) + +assert float('+Inf') > 0 +assert float('-Inf') < 0 + +assert float('3.14') == 3.14 +assert float('2.99e-23') == 2.99e-23 + +assert float(b'3.14') == 3.14 +assert float(b'2.99e-23') == 2.99e-23 + +assert_raises(lambda _: float('foo'), ValueError) +assert_raises(lambda _: float(2**10000), OverflowError) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index a4fecade7a..0dc048c8ce 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -21,3 +21,4 @@ statrs = "0.10.0" caseless = "0.2.1" unicode-segmentation = "1.2.1" lazy_static = "^1.0.1" +lexical = "2.0.0" diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 53f2bf756c..58f8fc9717 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -9,6 +9,7 @@ extern crate bitflags; #[macro_use] extern crate lazy_static; +extern crate lexical; #[macro_use] extern crate log; // extern crate env_logger; diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index a822f7208f..aba3158cc7 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -2,7 +2,9 @@ use super::super::pyobject::{ PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::VirtualMachine; +use super::objbytes; use super::objint; +use super::objstr; use super::objtype; use num_bigint::ToBigInt; use num_traits::ToPrimitive; @@ -23,9 +25,35 @@ fn float_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let val = if objtype::isinstance(arg, &vm.ctx.float_type()) { get_value(arg) } else if objtype::isinstance(arg, &vm.ctx.int_type()) { - objint::get_value(arg).to_f64().unwrap() + match objint::get_value(arg).to_f64() { + Some(f) => f, + None => { + return Err(vm.new_overflow_error("int too large to convert to float".to_string())); + } + } + } else if objtype::isinstance(arg, &vm.ctx.str_type()) { + match lexical::try_parse(objstr::get_value(arg)) { + Ok(f) => f, + Err(_) => { + let arg_repr = vm.to_pystr(arg)?; + return Err( + vm.new_value_error(format!("could not convert string to float: {}", arg_repr)) + ); + } + } + } else if objtype::isinstance(arg, &vm.ctx.bytes_type()) { + match lexical::try_parse(objbytes::get_value(arg).as_slice()) { + Ok(f) => f, + Err(_) => { + let arg_repr = vm.to_pystr(arg)?; + return Err( + vm.new_value_error(format!("could not convert string to float: {}", arg_repr)) + ); + } + } } else { - return Err(vm.new_type_error("Cannot construct int".to_string())); + let type_name = objtype::get_type_name(&arg.typ()); + return Err(vm.new_type_error(format!("can't convert {} to float", type_name))); }; set_value(zelf, val); Ok(vm.get_none())