Browse Source

Spec Compliant `Number.prototype.toString()`, better `Number` object formating and `-0` (#572)

* `Number` object formating and `-0`

* Made `Number.prototype.toString()` spec compliant

* Enabled ignore `toString()` tests
pull/579/head
HalidOdat 4 years ago committed by GitHub
parent
commit
08a608a821
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      Cargo.lock
  2. 26
      boa/src/builtins/number/mod.rs
  3. 47
      boa/src/builtins/number/tests.rs
  4. 21
      boa/src/builtins/value/display.rs

45
Cargo.lock generated

@ -421,9 +421,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.41"
version = "0.3.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916"
checksum = "52732a3d3ad72c58ad2dc70624f9c17b46ecd0943b9a4f1ee37c4c18c5d983e2"
dependencies = [
"wasm-bindgen",
]
@ -451,9 +451,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.8"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
]
@ -723,9 +723,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.1.56"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_users"
@ -819,8 +819,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "ryu-js"
version = "1.0.5"
source = "git+https://github.com/Tropid/ryu-js#fe366fa397d04324fa693b5d85134851b09719b3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1010bb9c1f68556b130d631f92fa5e78a2f15a7befcbfbbba51bdb35088149e9"
[[package]]
name = "same-file"
@ -924,9 +925,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
dependencies = [
"proc-macro2",
"quote",
@ -1045,9 +1046,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
version = "0.2.64"
version = "0.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2"
checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -1055,9 +1056,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.64"
version = "0.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df"
checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d"
dependencies = [
"bumpalo",
"lazy_static",
@ -1070,9 +1071,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.64"
version = "0.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8"
checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -1080,9 +1081,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.64"
version = "0.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75"
checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6"
dependencies = [
"proc-macro2",
"quote",
@ -1093,15 +1094,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.64"
version = "0.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae"
checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87"
[[package]]
name = "web-sys"
version = "0.3.41"
version = "0.3.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d"
checksum = "8be2398f326b7ba09815d0b403095f34dd708579220d099caae89be0b32137b2"
dependencies = [
"js-sys",
"wasm-bindgen",

26
boa/src/builtins/number/mod.rs

@ -361,18 +361,8 @@ impl Number {
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_native_string(x: f64) -> String {
if x == -0. {
return "0".to_owned();
} else if x.is_nan() {
return "NaN".to_owned();
} else if x.is_infinite() && x.is_sign_positive() {
return "Infinity".to_owned();
} else if x.is_infinite() && x.is_sign_negative() {
return "-Infinity".to_owned();
}
// FIXME: This is not spec compliant.
format!("{}", x)
let mut buffer = ryu_js::Buffer::new();
buffer.format(x).to_string()
}
/// `Number.prototype.toString( [radix] )`
@ -400,6 +390,11 @@ impl Number {
.throw_range_error("radix must be an integer at least 2 and no greater than 36");
}
// 5. If radixNumber = 10, return ! ToString(x).
if radix == 10 {
return Ok(Value::from(Self::to_native_string(x)));
}
if x == -0. {
return Ok(Value::from("0"));
} else if x.is_nan() {
@ -410,13 +405,6 @@ impl Number {
return Ok(Value::from("-Infinity"));
}
// 5. If radixNumber = 10, return ! ToString(x).
// This part should use exponential notations for long integer numbers commented tests
if radix == 10 {
// return Ok(to_value(format!("{}", Self::to_number(this).to_num())));
return Ok(Value::from(Self::to_native_string(x)));
}
// This is a Optimization from the v8 source code to print values that can fit in a single character
// Since the actual num_to_string allocates a 2200 bytes buffer for actual conversion
// I am not sure if this part is effective as the v8 equivalent https://chromium.googlesource.com/v8/v8/+/refs/heads/master/src/builtins/number.tq#53

47
boa/src/builtins/number/tests.rs

@ -328,49 +328,30 @@ fn to_string() {
}
#[test]
#[ignore]
// This tests fail for now since the Rust's default formatting for exponential format does not match the js spec.
// https://github.com/jasonwilliams/boa/pull/381#discussion_r422458544
fn num_to_string_exponential() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
assert_eq!("0", forward(&mut engine, "(0).toString()"));
assert_eq!("0", forward(&mut engine, "(-0).toString()"));
assert_eq!(
String::from("111111111111111110000"),
forward(&mut engine, "Number(111111111111111111111).toString()")
);
assert_eq!(
String::from("1.1111111111111111e+21"),
forward(&mut engine, "Number(1111111111111111111111).toString()")
);
assert_eq!(
String::from("1.1111111111111111e+22"),
forward(&mut engine, "Number(11111111111111111111111).toString()")
);
assert_eq!(
String::from("1e-7"),
forward(&mut engine, "Number(0.0000001).toString()")
);
assert_eq!(
String::from("1.2e-7"),
forward(&mut engine, "Number(0.00000012).toString()")
);
assert_eq!(
String::from("1.23e-7"),
forward(&mut engine, "Number(0.000000123).toString()")
);
assert_eq!(
String::from("1e-8"),
forward(&mut engine, "Number(0.00000001).toString()")
"111111111111111110000",
forward(&mut engine, "(111111111111111111111).toString()")
);
assert_eq!(
String::from("1.2e-8"),
forward(&mut engine, "Number(0.000000012).toString()")
"1.1111111111111111e+21",
forward(&mut engine, "(1111111111111111111111).toString()")
);
assert_eq!(
String::from("1.23e-8"),
forward(&mut engine, "Number(0.0000000123).toString()")
"1.1111111111111111e+22",
forward(&mut engine, "(11111111111111111111111).toString()")
);
assert_eq!("1e-7", forward(&mut engine, "(0.0000001).toString()"));
assert_eq!("1.2e-7", forward(&mut engine, "(0.00000012).toString()"));
assert_eq!("1.23e-7", forward(&mut engine, "(0.000000123).toString()"));
assert_eq!("1e-8", forward(&mut engine, "(0.00000001).toString()"));
assert_eq!("1.2e-8", forward(&mut engine, "(0.000000012).toString()"));
assert_eq!("1.23e-8", forward(&mut engine, "(0.0000000123).toString()"));
}
#[test]

21
boa/src/builtins/value/display.rs

@ -67,6 +67,14 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children:
match v.borrow().data {
ObjectData::String(ref string) => format!("String {{ \"{}\" }}", string),
ObjectData::Boolean(boolean) => format!("Boolean {{ {} }}", boolean),
ObjectData::Number(rational) => {
if rational.is_sign_negative() && rational == 0.0 {
"Number { -0 }".to_string()
} else {
let mut buffer = ryu_js::Buffer::new();
format!("Number {{ {} }}", buffer.format(rational))
}
}
ObjectData::Array => {
let len = i32::from(
&v.borrow()
@ -219,7 +227,16 @@ impl Display for Value {
}
}
/// This is different from the ECMAScript compliant number to string, in the printing of `-0`.
///
/// This function prints `-0` as `-0` instead of pasitive `0` as the specification says.
/// This is done to make it easer for the user of the REPL to identify what is a `-0` vs `0`,
/// since the REPL is not bound to the ECMAScript specification we can do this.
fn format_rational(v: f64, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer = ryu_js::Buffer::new();
write!(f, "{}", buffer.format(v))
if v.is_sign_negative() && v == 0.0 {
f.write_str("-0")
} else {
let mut buffer = ryu_js::Buffer::new();
write!(f, "{}", buffer.format(v))
}
}

Loading…
Cancel
Save