fix(es/minifier): Fix toFixed, toPrecision, toExponential and toString of Number (#6960)

This commit is contained in:
magic-akari 2023-02-19 22:18:14 +08:00 committed by GitHub
parent 6f18f23326
commit 9382bda786
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1374 additions and 45 deletions

View File

@ -19,6 +19,7 @@ crates/swc_css_parser/tests/
crates/swc_css_prefixer/tests/
crates/swc_ecma_codegen/tests/
crates/swc_ecma_lints/tests/
crates/swc_ecma_minifier/tests/
crates/swc_ecma_parser/tests/
crates/swc_estree_compat/tests/
crates/swc_html_codegen/tests/

7
Cargo.lock generated
View File

@ -2676,6 +2676,12 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "ryu-js"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f"
[[package]]
name = "same-file"
version = "1.0.6"
@ -3682,6 +3688,7 @@ dependencies = [
"rayon",
"regex",
"rustc-hash",
"ryu-js",
"serde",
"serde_json",
"swc_atoms",

View File

@ -2,4 +2,3 @@
import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
import _sliced_to_array from "@swc/helpers/src/_sliced_to_array.mjs";
import _to_array from "@swc/helpers/src/_to_array.mjs";
0..toExponential();

View File

@ -1,2 +1,2 @@
//// [numberPropertyAccess.ts]
1..toExponential(), 1..hasOwnProperty("toFixed"), 1..toExponential(), 1..hasOwnProperty("toFixed");
1..hasOwnProperty("toFixed"), 1..hasOwnProperty("toFixed");

View File

@ -42,6 +42,7 @@ radix_fmt = "=1.0.0"
rayon = {version = "1.5.1", optional = true}
regex = "1.5.3"
rustc-hash = "1.1.0"
ryu-js = "0.2.2"
serde = {version = "1.0.118", features = ["derive"]}
serde_json = "1.0.61"
swc_atoms = {version = "0.4.36", path = "../swc_atoms"}

View File

@ -315,15 +315,67 @@ impl Pure<'_> {
}
if &*method.sym == "toFixed" {
// https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.tofixed
//
// Note 1: This method returns a String containing this Number value represented
// in decimal fixed-point notation with fractionDigits digits after the decimal
// point. If fractionDigits is undefined, 0 is assumed.
// Note 2: The output of toFixed may be more precise than toString for some
// values because toString only prints enough significant digits to distinguish
// the number from adjacent Number values. For example,
//
// (1000000000000000128).toString() returns "1000000000000000100", while
// (1000000000000000128).toFixed(0) returns "1000000000000000128".
// 1. Let x be ? thisNumberValue(this value).
// 2. Let f be ? ToIntegerOrInfinity(fractionDigits).
if let Some(precision) = args
.first()
// https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.tofixed
// 3. Assert: If fractionDigits is undefined, then f is 0.
.map_or(Some(0f64), |arg| eval_as_number(&self.expr_ctx, &arg.expr))
{
if precision.fract() == 0.0 {
let precision = precision.floor() as usize;
let value = num_to_fixed(num.value, precision + 1);
let f = precision.trunc() as usize;
// 4. If f is not finite, throw a RangeError exception.
// 5. If f < 0 or f > 100, throw a RangeError exception.
// Note: ES2018 increased the maximum number of fraction digits from 20 to 100.
// It relies on runtime behavior.
if !(0..=20).contains(&f) {
return;
}
// 6. If x is not finite, return Number::toString(x, 10).
let x = {
let x = num.value;
// 7. Set x to (x).
if x == -0. {
0.
} else {
x
}
};
// 8. Let s be the empty String.
// 9. If x < 0, then
// a. Set s to "-".
// b. Set x to -x.
// 10. If x ≥ 10**21, then
// a. Let m be ! ToString(𝔽(x)).
let value = if x >= 1e21 || x <= -1e21 {
format!("{:e}", x).replace('e', "e+")
} else {
// 11. Else,
if x.fract() != 0. && f != 0 {
// TODO: rust built-in format cannot handle ecma262 `1.25.toFixed(1)`
return;
} else {
format!("{:.*}", f, x)
}
};
self.changed = true;
report_change!(
@ -339,21 +391,136 @@ impl Pure<'_> {
value: value.into(),
}));
}
}
return;
}
if &*method.sym == "toPrecision" {
// TODO: handle num.toPrecision(undefined)
if args.first().is_none() {
// https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.toprecision
// 2. If precision is undefined, return ! ToString(x).
let value = ryu_js::Buffer::new().format(num.value).to_string().into();
self.changed = true;
report_change!(
"evaluate: Evaluating `{}.toPrecision()` as `{}`",
num,
value
);
*e = Expr::Lit(Lit::Str(Str {
span: e.span(),
raw: None,
value,
}));
return;
}
if let Some(precision) = args
.first()
.and_then(|arg| eval_as_number(&self.expr_ctx, &arg.expr))
{
let p = precision.trunc() as usize;
// 5. If p < 1 or p > 100, throw a RangeError exception.
if !(1..=21).contains(&p) {
return;
}
let value = f64_to_precision(num.value, p);
self.changed = true;
report_change!(
"evaluate: Evaluating `{}.toPrecision()` as `{}`",
num,
value
);
*e = Expr::Lit(Lit::Str(Str {
span: e.span(),
raw: None,
value: value.into(),
}));
return;
}
}
if &*method.sym == "toExponential" {
// TODO: handle num.toExponential(undefined)
if args.first().is_none() {
let value = f64_to_exponential(num.value).into();
self.changed = true;
report_change!(
"evaluate: Evaluating `{}.toExponential()` as `{}`",
num,
value
);
*e = Expr::Lit(Lit::Str(Str {
span: e.span(),
raw: None,
value,
}));
return;
} else if let Some(precision) = args
.first()
.and_then(|arg| eval_as_number(&self.expr_ctx, &arg.expr))
{
let p = precision.trunc() as usize;
// 5. If p < 1 or p > 100, throw a RangeError exception.
if !(0..=20).contains(&p) {
return;
}
let value = f64_to_exponential_with_precision(num.value, p).into();
self.changed = true;
report_change!(
"evaluate: Evaluating `{}.toPrecision({})` as `{}`",
num,
precision,
value
);
*e = Expr::Lit(Lit::Str(Str {
span: e.span(),
raw: None,
value,
}));
return;
}
}
if &*method.sym == "toString" {
if let Some(base) = args
.first()
.map_or(Some(10f64), |arg| eval_as_number(&self.expr_ctx, &arg.expr))
{
if base.trunc() == 10. {
let value = ryu_js::Buffer::new().format(num.value).to_string().into();
*e = Expr::Lit(Lit::Str(Str {
span: e.span(),
raw: None,
value,
}));
return;
}
if num.value.fract() == 0.0 && (2.0..=36.0).contains(&base) && base.fract() == 0.0 {
let base = base.floor() as u8;
self.changed = true;
let value = Radix::new(num.value as usize, base).to_string().into();
let value = {
let x = num.value;
if x < 0. {
// I don't know if u128 is really needed, but it works.
format!("-{}", Radix::new(-x as u128, base))
} else {
Radix::new(x as u128, base).to_string()
}
}
.into();
*e = Expr::Lit(Lit::Str(Str {
span: e.span(),
raw: None,
@ -603,31 +770,183 @@ impl Pure<'_> {
}
}
/// https://stackoverflow.com/questions/60497397/how-do-you-format-a-float-to-the-first-significant-decimal-and-with-specified-pr
fn num_to_fixed(float: f64, precision: usize) -> String {
// compute absolute value
let a = float.abs();
// Code from boa
// https://github.com/boa-dev/boa/blob/f8b682085d7fe0bbfcd0333038e93cf2f5aee710/boa_engine/src/builtins/number/mod.rs#L408
fn f64_to_precision(value: f64, precision: usize) -> String {
let mut x = value;
let p_i32 = precision as i32;
// if abs value is greater than 1, then precision becomes less than "standard"
let precision = if a >= 1. {
// reduce by number of digits, minimum 0
let n = (1. + a.log10().floor()) as usize;
if n <= precision {
precision - n
} else {
0
// 7. Let s be the empty String.
let mut s = String::new();
let mut m: String;
let mut e: i32;
// 8. If x < 0, then
// a. Set s to the code unit 0x002D (HYPHEN-MINUS).
// b. Set x to -x.
if x < 0. {
s.push('-');
x = -x;
}
// if precision is less than 1 (but non-zero), then precision becomes
// greater than "standard"
} else if a > 0. {
// increase number of digits
let n = -(1. + a.log10().floor()) as usize;
precision + n
// special case for 0
// 9. If x = 0, then
// a. Let m be the String value consisting of p occurrences of the code unit
// 0x0030 (DIGIT ZERO).
// b. Let e be 0.
if x == 0.0 {
m = "0".repeat(precision);
e = 0;
// 10
} else {
0
// Due to f64 limitations, this part differs a bit from the spec,
// but has the same effect. It manipulates the string constructed
// by `format`: digits with an optional dot between two of them.
m = format!("{x:.100}");
// a: getting an exponent
e = flt_str_to_exp(&m);
// b: getting relevant digits only
if e < 0 {
m = m.split_off((1 - e) as usize);
} else if let Some(n) = m.find('.') {
m.remove(n);
}
// impl: having exactly `precision` digits in `suffix`
if round_to_precision(&mut m, precision) {
e += 1;
}
// c: switching to scientific notation
let great_exp = e >= p_i32;
if e < -6 || great_exp {
assert_ne!(e, 0);
// ii
if precision > 1 {
m.insert(1, '.');
}
// vi
m.push('e');
// iii
if great_exp {
m.push('+');
}
// iv, v
m.push_str(&e.to_string());
return s + &m;
}
}
// 11
let e_inc = e + 1;
if e_inc == p_i32 {
return s + &m;
}
// 12
if e >= 0 {
m.insert(e_inc as usize, '.');
// 13
} else {
s.push('0');
s.push('.');
s.push_str(&"0".repeat(-e_inc as usize));
}
// 14
s + &m
}
fn flt_str_to_exp(flt: &str) -> i32 {
let mut non_zero_encountered = false;
let mut dot_encountered = false;
for (i, c) in flt.chars().enumerate() {
if c == '.' {
if non_zero_encountered {
return (i as i32) - 1;
}
dot_encountered = true;
} else if c != '0' {
if dot_encountered {
return 1 - (i as i32);
}
non_zero_encountered = true;
}
}
(flt.len() as i32) - 1
}
fn round_to_precision(digits: &mut String, precision: usize) -> bool {
if digits.len() > precision {
let to_round = digits.split_off(precision);
let mut digit = digits
.pop()
.expect("already checked that length is bigger than precision")
as u8;
if let Some(first) = to_round.chars().next() {
if first > '4' {
digit += 1;
}
}
if digit as char == ':' {
// ':' is '9' + 1
// need to propagate the increment backward
let mut replacement = String::from("0");
let mut propagated = false;
for c in digits.chars().rev() {
let d = match (c, propagated) {
('0'..='8', false) => (c as u8 + 1) as char,
(_, false) => '0',
(_, true) => c,
};
// format with the given computed precision
format!("{0:.1$}", float, precision)
replacement.push(d);
if d != '0' {
propagated = true;
}
}
digits.clear();
let replacement = if propagated {
replacement.as_str()
} else {
digits.push('1');
&replacement.as_str()[1..]
};
for c in replacement.chars().rev() {
digits.push(c);
}
!propagated
} else {
digits.push(digit as char);
false
}
} else {
digits.push_str(&"0".repeat(precision - digits.len()));
false
}
}
/// Helper function that formats a float as a ES6-style exponential number
/// string.
fn f64_to_exponential(n: f64) -> String {
match n.abs() {
x if x >= 1.0 || x == 0.0 => format!("{n:e}").replace('e', "e+"),
_ => format!("{n:e}"),
}
}
/// Helper function that formats a float as a ES6-style exponential number
/// string with a given precision.
// We can't use the same approach as in `f64_to_exponential`
// because in cases like (0.999).toExponential(0) the result will be 1e0.
// Instead we get the index of 'e', and if the next character is not '-'
// we insert the plus sign
fn f64_to_exponential_with_precision(n: f64, prec: usize) -> String {
let mut res = format!("{n:.prec$e}");
let idx = res.find('e').expect("'e' not found in exponential string");
if res.as_bytes()[idx + 1] != b'-' {
res.insert(idx + 1, '+');
}
res
}

View File

@ -6018,7 +6018,7 @@
$({
target: "Number",
proto: !0,
forced: nativeToFixed && !0 || !fails(function() {
forced: nativeToFixed && ("0.000" !== 0.00008.toFixed(3) || "1.25" !== 1.255.toFixed(2)) || !fails(function() {
nativeToFixed.call({});
})
}, {

View File

@ -0,0 +1,46 @@
{
"arguments": false,
"arrows": true,
"booleans": true,
"booleans_as_integers": false,
"collapse_vars": true,
"comparisons": true,
"computed_props": true,
"conditionals": true,
"dead_code": true,
"directives": true,
"drop_console": false,
"drop_debugger": true,
"evaluate": true,
"expression": false,
"hoist_funs": false,
"hoist_props": true,
"hoist_vars": false,
"if_return": true,
"join_vars": true,
"keep_classnames": false,
"keep_fargs": true,
"keep_fnames": false,
"keep_infinity": false,
"loops": true,
"negate_iife": true,
"properties": true,
"reduce_funcs": false,
"reduce_vars": false,
"side_effects": true,
"switches": true,
"typeofs": true,
"unsafe": false,
"unsafe_arrows": false,
"unsafe_comps": false,
"unsafe_Function": false,
"unsafe_math": false,
"unsafe_symbols": false,
"unsafe_methods": false,
"unsafe_proto": false,
"unsafe_regexp": false,
"unsafe_undefined": false,
"unused": true,
"const_to_let": true,
"pristine_globals": true
}

View File

@ -0,0 +1,21 @@
// prettier-ignore
export function foo() {
// actual | expected
alert(1..toFixed(1)) // '1.0' '1.0'
alert(0..toFixed(0)) // '0' '0'
alert(0..toFixed(1)) // '0' '0.0'
alert(0..toFixed(2)) // '0' '0.00'
alert(0..toFixed(3)) // '0' '0.000'
alert(10..toFixed(1)) // '10' '10.0'
alert(20..toFixed(2)) // '20.0' '20.00'
alert(30..toFixed(3)) // '30.00' '30.000'
alert(100..toFixed(1)) // '100' '100.0'
alert(100..toFixed(2)) // '100' '100.00'
alert(100..toFixed(3)) // '100.0' '100.000'
alert(110..toFixed(1)) // '110' '110.0'
alert(110..toFixed(2)) // '110' '110.00'
alert(110..toFixed(3)) // '110.0' '110.000'
alert(110..toFixed(4)) // '110.00' '110.000'
alert(1110..toFixed(4)) // '1110.0' '1110.0000'
alert(11110..toFixed(4)) // '11110' '11110.0000'
}

View File

@ -0,0 +1,19 @@
export function foo() {
alert("1.0");
alert("0");
alert("0.0");
alert("0.00");
alert("0.000");
alert("10.0");
alert("20.00");
alert("30.000");
alert("100.0");
alert("100.00");
alert("100.000");
alert("110.0");
alert("110.00");
alert("110.000");
alert("110.0000");
alert("1110.0000");
alert("11110.0000");
}

View File

@ -0,0 +1,46 @@
{
"arguments": false,
"arrows": true,
"booleans": true,
"booleans_as_integers": false,
"collapse_vars": true,
"comparisons": true,
"computed_props": true,
"conditionals": true,
"dead_code": true,
"directives": true,
"drop_console": false,
"drop_debugger": true,
"evaluate": true,
"expression": false,
"hoist_funs": false,
"hoist_props": true,
"hoist_vars": false,
"if_return": true,
"join_vars": true,
"keep_classnames": false,
"keep_fargs": true,
"keep_fnames": false,
"keep_infinity": false,
"loops": true,
"negate_iife": true,
"properties": true,
"reduce_funcs": false,
"reduce_vars": false,
"side_effects": true,
"switches": true,
"typeofs": true,
"unsafe": false,
"unsafe_arrows": false,
"unsafe_comps": false,
"unsafe_Function": false,
"unsafe_math": false,
"unsafe_symbols": false,
"unsafe_methods": false,
"unsafe_proto": false,
"unsafe_regexp": false,
"unsafe_undefined": false,
"unused": true,
"const_to_let": true,
"pristine_globals": true
}

View File

@ -0,0 +1,108 @@
// Copyright (C) 2016 The V8 Project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-number.prototype.toprecision
description: >
Return string values using exponential character
info: |
Number.prototype.toPrecision ( precision )
1. Let x be ? thisNumberValue(this value).
[...]
5. Let s be the empty String.
[...]
9. If x = 0, then
[...]
10. Else x 0,
[...]
c. If e < -6 or e p, then
[...]
vii. Return the concatenation of s, m, code unit 0x0065 (LATIN SMALL
LETTER E), c, and d.
[...]
---*/
assert.sameValue((10).toPrecision(1), "1e+1");
assert.sameValue((11).toPrecision(1), "1e+1");
assert.sameValue((17).toPrecision(1), "2e+1");
assert.sameValue((19).toPrecision(1), "2e+1");
assert.sameValue((20).toPrecision(1), "2e+1");
assert.sameValue((100).toPrecision(1), "1e+2");
assert.sameValue((1000).toPrecision(1), "1e+3");
assert.sameValue((10000).toPrecision(1), "1e+4");
assert.sameValue((100000).toPrecision(1), "1e+5");
assert.sameValue((100).toPrecision(2), "1.0e+2");
assert.sameValue((1000).toPrecision(2), "1.0e+3");
assert.sameValue((10000).toPrecision(2), "1.0e+4");
assert.sameValue((100000).toPrecision(2), "1.0e+5");
assert.sameValue((1000).toPrecision(3), "1.00e+3");
assert.sameValue((10000).toPrecision(3), "1.00e+4");
assert.sameValue((100000).toPrecision(3), "1.00e+5");
assert.sameValue((42).toPrecision(1), "4e+1");
assert.sameValue((-42).toPrecision(1), "-4e+1");
assert.sameValue((1.2345e+27).toPrecision(1), "1e+27");
assert.sameValue((1.2345e+27).toPrecision(2), "1.2e+27");
assert.sameValue((1.2345e+27).toPrecision(3), "1.23e+27");
assert.sameValue((1.2345e+27).toPrecision(4), "1.234e+27");
assert.sameValue((1.2345e+27).toPrecision(5), "1.2345e+27");
assert.sameValue((1.2345e+27).toPrecision(6), "1.23450e+27");
assert.sameValue((1.2345e+27).toPrecision(7), "1.234500e+27");
assert.sameValue((1.2345e+27).toPrecision(16), "1.234500000000000e+27");
assert.sameValue((1.2345e+27).toPrecision(17), "1.2345000000000000e+27");
assert.sameValue((1.2345e+27).toPrecision(18), "1.23449999999999996e+27");
assert.sameValue((1.2345e+27).toPrecision(19), "1.234499999999999962e+27");
assert.sameValue((1.2345e+27).toPrecision(20), "1.2344999999999999618e+27");
assert.sameValue((1.2345e+27).toPrecision(21), "1.23449999999999996184e+27");
assert.sameValue((-1.2345e+27).toPrecision(1), "-1e+27");
assert.sameValue((-1.2345e+27).toPrecision(2), "-1.2e+27");
assert.sameValue((-1.2345e+27).toPrecision(3), "-1.23e+27");
assert.sameValue((-1.2345e+27).toPrecision(4), "-1.234e+27");
assert.sameValue((-1.2345e+27).toPrecision(5), "-1.2345e+27");
assert.sameValue((-1.2345e+27).toPrecision(6), "-1.23450e+27");
assert.sameValue((-1.2345e+27).toPrecision(7), "-1.234500e+27");
assert.sameValue((-1.2345e+27).toPrecision(16), "-1.234500000000000e+27");
assert.sameValue((-1.2345e+27).toPrecision(17), "-1.2345000000000000e+27");
assert.sameValue((-1.2345e+27).toPrecision(18), "-1.23449999999999996e+27");
assert.sameValue((-1.2345e+27).toPrecision(19), "-1.234499999999999962e+27");
assert.sameValue((-1.2345e+27).toPrecision(20), "-1.2344999999999999618e+27");
assert.sameValue((-1.2345e+27).toPrecision(21), "-1.23449999999999996184e+27");
var n = new Number("1000000000000000000000"); // 1e+21
assert.sameValue((n).toPrecision(1), "1e+21");
assert.sameValue((n).toPrecision(2), "1.0e+21");
assert.sameValue((n).toPrecision(3), "1.00e+21");
assert.sameValue((n).toPrecision(4), "1.000e+21");
assert.sameValue((n).toPrecision(5), "1.0000e+21");
assert.sameValue((n).toPrecision(6), "1.00000e+21");
assert.sameValue((n).toPrecision(7), "1.000000e+21");
assert.sameValue((n).toPrecision(16), "1.000000000000000e+21");
assert.sameValue((n).toPrecision(17), "1.0000000000000000e+21");
assert.sameValue((n).toPrecision(18), "1.00000000000000000e+21");
assert.sameValue((n).toPrecision(19), "1.000000000000000000e+21");
assert.sameValue((n).toPrecision(20), "1.0000000000000000000e+21");
assert.sameValue((n).toPrecision(21), "1.00000000000000000000e+21");
var n = new Number("0.000000000000000000001"); // 1e-21
assert.sameValue((n).toPrecision(1), "1e-21");
assert.sameValue((n).toPrecision(2), "1.0e-21");
assert.sameValue((n).toPrecision(3), "1.00e-21");
assert.sameValue((n).toPrecision(4), "1.000e-21");
assert.sameValue((n).toPrecision(5), "1.0000e-21");
assert.sameValue((n).toPrecision(6), "1.00000e-21");
assert.sameValue((n).toPrecision(7), "1.000000e-21");
assert.sameValue((n).toPrecision(16), "9.999999999999999e-22");
assert.sameValue((n).toPrecision(17), "9.9999999999999991e-22");
assert.sameValue((n).toPrecision(18), "9.99999999999999908e-22");
assert.sameValue((n).toPrecision(19), "9.999999999999999075e-22");
assert.sameValue((n).toPrecision(20), "9.9999999999999990754e-22");
assert.sameValue((n).toPrecision(21), "9.99999999999999907537e-22");
assert.sameValue((0.00000001).toPrecision(1), "1e-8");
assert.sameValue((-0.00000001).toPrecision(1), "-1e-8");

View File

@ -0,0 +1,74 @@
assert.sameValue("1e+1", "1e+1");
assert.sameValue("1e+1", "1e+1");
assert.sameValue("2e+1", "2e+1");
assert.sameValue("2e+1", "2e+1");
assert.sameValue("2e+1", "2e+1");
assert.sameValue("1e+2", "1e+2");
assert.sameValue("1e+3", "1e+3");
assert.sameValue("1e+4", "1e+4");
assert.sameValue("1e+5", "1e+5");
assert.sameValue("1.0e+2", "1.0e+2");
assert.sameValue("1.0e+3", "1.0e+3");
assert.sameValue("1.0e+4", "1.0e+4");
assert.sameValue("1.0e+5", "1.0e+5");
assert.sameValue("1.00e+3", "1.00e+3");
assert.sameValue("1.00e+4", "1.00e+4");
assert.sameValue("1.00e+5", "1.00e+5");
assert.sameValue("4e+1", "4e+1");
assert.sameValue("-4e+1", "-4e+1");
assert.sameValue("1e+27", "1e+27");
assert.sameValue("1.2e+27", "1.2e+27");
assert.sameValue("1.23e+27", "1.23e+27");
assert.sameValue("1.234e+27", "1.234e+27");
assert.sameValue("1.2345e+27", "1.2345e+27");
assert.sameValue("1.23450e+27", "1.23450e+27");
assert.sameValue("1.234500e+27", "1.234500e+27");
assert.sameValue("1.234500000000000e+27", "1.234500000000000e+27");
assert.sameValue("1.2345000000000000e+27", "1.2345000000000000e+27");
assert.sameValue("1.23449999999999996e+27", "1.23449999999999996e+27");
assert.sameValue("1.234499999999999962e+27", "1.234499999999999962e+27");
assert.sameValue("1.2344999999999999618e+27", "1.2344999999999999618e+27");
assert.sameValue("1.23449999999999996184e+27", "1.23449999999999996184e+27");
assert.sameValue("-1e+27", "-1e+27");
assert.sameValue("-1.2e+27", "-1.2e+27");
assert.sameValue("-1.23e+27", "-1.23e+27");
assert.sameValue("-1.234e+27", "-1.234e+27");
assert.sameValue("-1.2345e+27", "-1.2345e+27");
assert.sameValue("-1.23450e+27", "-1.23450e+27");
assert.sameValue("-1.234500e+27", "-1.234500e+27");
assert.sameValue("-1.234500000000000e+27", "-1.234500000000000e+27");
assert.sameValue("-1.2345000000000000e+27", "-1.2345000000000000e+27");
assert.sameValue("-1.23449999999999996e+27", "-1.23449999999999996e+27");
assert.sameValue("-1.234499999999999962e+27", "-1.234499999999999962e+27");
assert.sameValue("-1.2344999999999999618e+27", "-1.2344999999999999618e+27");
assert.sameValue("-1.23449999999999996184e+27", "-1.23449999999999996184e+27");
var n = new Number("1000000000000000000000");
assert.sameValue(n.toPrecision(1), "1e+21");
assert.sameValue(n.toPrecision(2), "1.0e+21");
assert.sameValue(n.toPrecision(3), "1.00e+21");
assert.sameValue(n.toPrecision(4), "1.000e+21");
assert.sameValue(n.toPrecision(5), "1.0000e+21");
assert.sameValue(n.toPrecision(6), "1.00000e+21");
assert.sameValue(n.toPrecision(7), "1.000000e+21");
assert.sameValue(n.toPrecision(16), "1.000000000000000e+21");
assert.sameValue(n.toPrecision(17), "1.0000000000000000e+21");
assert.sameValue(n.toPrecision(18), "1.00000000000000000e+21");
assert.sameValue(n.toPrecision(19), "1.000000000000000000e+21");
assert.sameValue(n.toPrecision(20), "1.0000000000000000000e+21");
assert.sameValue(n.toPrecision(21), "1.00000000000000000000e+21");
var n = new Number("0.000000000000000000001");
assert.sameValue(n.toPrecision(1), "1e-21");
assert.sameValue(n.toPrecision(2), "1.0e-21");
assert.sameValue(n.toPrecision(3), "1.00e-21");
assert.sameValue(n.toPrecision(4), "1.000e-21");
assert.sameValue(n.toPrecision(5), "1.0000e-21");
assert.sameValue(n.toPrecision(6), "1.00000e-21");
assert.sameValue(n.toPrecision(7), "1.000000e-21");
assert.sameValue(n.toPrecision(16), "9.999999999999999e-22");
assert.sameValue(n.toPrecision(17), "9.9999999999999991e-22");
assert.sameValue(n.toPrecision(18), "9.99999999999999908e-22");
assert.sameValue(n.toPrecision(19), "9.999999999999999075e-22");
assert.sameValue(n.toPrecision(20), "9.9999999999999990754e-22");
assert.sameValue(n.toPrecision(21), "9.99999999999999907537e-22");
assert.sameValue("1e-8", "1e-8");
assert.sameValue("-1e-8", "-1e-8");

View File

@ -0,0 +1,46 @@
{
"arguments": false,
"arrows": true,
"booleans": true,
"booleans_as_integers": false,
"collapse_vars": true,
"comparisons": true,
"computed_props": true,
"conditionals": true,
"dead_code": true,
"directives": true,
"drop_console": false,
"drop_debugger": true,
"evaluate": true,
"expression": false,
"hoist_funs": false,
"hoist_props": true,
"hoist_vars": false,
"if_return": true,
"join_vars": true,
"keep_classnames": false,
"keep_fargs": true,
"keep_fnames": false,
"keep_infinity": false,
"loops": true,
"negate_iife": true,
"properties": true,
"reduce_funcs": false,
"reduce_vars": false,
"side_effects": true,
"switches": true,
"typeofs": true,
"unsafe": false,
"unsafe_arrows": false,
"unsafe_comps": false,
"unsafe_Function": false,
"unsafe_math": false,
"unsafe_symbols": false,
"unsafe_methods": false,
"unsafe_proto": false,
"unsafe_regexp": false,
"unsafe_undefined": false,
"unused": true,
"const_to_let": true,
"pristine_globals": true
}

View File

@ -0,0 +1,344 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------
// toString
assertEquals("NaN", (NaN).toString());
assertEquals("Infinity", (1/0).toString());
assertEquals("-Infinity", (-1/0).toString());
assertEquals("0", (0).toString());
assertEquals("9", (9).toString());
assertEquals("90", (90).toString());
assertEquals("90.12", (90.12).toString());
assertEquals("0.1", (0.1).toString());
assertEquals("0.01", (0.01).toString());
assertEquals("0.0123", (0.0123).toString());
assertEquals("111111111111111110000", (111111111111111111111).toString());
assertEquals("1.1111111111111111e+21", (1111111111111111111111).toString());
assertEquals("1.1111111111111111e+22", (11111111111111111111111).toString());
assertEquals("0.00001", (0.00001).toString());
assertEquals("0.000001", (0.000001).toString());
assertEquals("1e-7", (0.0000001).toString());
assertEquals("1.2e-7", (0.00000012).toString());
assertEquals("1.23e-7", (0.000000123).toString());
assertEquals("1e-8", (0.00000001).toString());
assertEquals("1.2e-8", (0.000000012).toString());
assertEquals("1.23e-8", (0.0000000123).toString());
assertEquals("0", (-0).toString());
assertEquals("-9", (-9).toString());
assertEquals("-90", (-90).toString());
assertEquals("-90.12", (-90.12).toString());
assertEquals("-0.1", (-0.1).toString());
assertEquals("-0.01", (-0.01).toString());
assertEquals("-0.0123", (-0.0123).toString());
assertEquals("-111111111111111110000", (-111111111111111111111).toString());
assertEquals("-1.1111111111111111e+21", (-1111111111111111111111).toString());
assertEquals("-1.1111111111111111e+22", (-11111111111111111111111).toString());
assertEquals("-0.00001", (-0.00001).toString());
assertEquals("-0.000001", (-0.000001).toString());
assertEquals("-1e-7", (-0.0000001).toString());
assertEquals("-1.2e-7", (-0.00000012).toString());
assertEquals("-1.23e-7", (-0.000000123).toString());
assertEquals("-1e-8", (-0.00000001).toString());
assertEquals("-1.2e-8", (-0.000000012).toString());
assertEquals("-1.23e-8", (-0.0000000123).toString());
assertEquals("NaN", (NaN).toString(16));
assertEquals("Infinity", (1/0).toString(16));
assertEquals("-Infinity", (-1/0).toString(16));
assertEquals("0", (0).toString(16));
assertEquals("9", (9).toString(16));
assertEquals("5a", (90).toString(16));
assertEquals("5a.1eb851eb852", (90.12).toString(16));
assertEquals("0.1999999999999a", (0.1).toString(16));
assertEquals("0.028f5c28f5c28f6", (0.01).toString(16));
assertEquals("0.032617c1bda511a", (0.0123).toString(16));
assertEquals("605f9f6dd18bc8000", (111111111111111111111).toString(16));
assertEquals("3c3bc3a4a2f75c0000", (1111111111111111111111).toString(16));
assertEquals("25a55a46e5da9a00000", (11111111111111111111111).toString(16));
assertEquals("0.0000a7c5ac471b4788", (0.00001).toString(16));
assertEquals("0.000010c6f7a0b5ed8d", (0.000001).toString(16));
assertEquals("0.000001ad7f29abcaf48", (0.0000001).toString(16));
assertEquals("0.000002036565348d256", (0.00000012).toString(16));
assertEquals("0.0000021047ee22aa466", (0.000000123).toString(16));
assertEquals("0.0000002af31dc4611874", (0.00000001).toString(16));
assertEquals("0.000000338a23b87483be", (0.000000012).toString(16));
assertEquals("0.00000034d3fe36aaa0a2", (0.0000000123).toString(16));
assertEquals("0", (-0).toString(16));
assertEquals("-9", (-9).toString(16));
assertEquals("-5a", (-90).toString(16));
assertEquals("-5a.1eb851eb852", (-90.12).toString(16));
assertEquals("-0.1999999999999a", (-0.1).toString(16));
assertEquals("-0.028f5c28f5c28f6", (-0.01).toString(16));
assertEquals("-0.032617c1bda511a", (-0.0123).toString(16));
assertEquals("-605f9f6dd18bc8000", (-111111111111111111111).toString(16));
assertEquals("-3c3bc3a4a2f75c0000", (-1111111111111111111111).toString(16));
assertEquals("-25a55a46e5da9a00000", (-11111111111111111111111).toString(16));
assertEquals("-0.0000a7c5ac471b4788", (-0.00001).toString(16));
assertEquals("-0.000010c6f7a0b5ed8d", (-0.000001).toString(16));
assertEquals("-0.000001ad7f29abcaf48", (-0.0000001).toString(16));
assertEquals("-0.000002036565348d256", (-0.00000012).toString(16));
assertEquals("-0.0000021047ee22aa466", (-0.000000123).toString(16));
assertEquals("-0.0000002af31dc4611874", (-0.00000001).toString(16));
assertEquals("-0.000000338a23b87483be", (-0.000000012).toString(16));
assertEquals("-0.00000034d3fe36aaa0a2", (-0.0000000123).toString(16));
assertEquals("4294967296", Math.pow(2,32).toString());
assertEquals("ffffffff", (Math.pow(2,32)-1).toString(16));
assertEquals("11111111111111111111111111111111", (Math.pow(2,32)-1).toString(2));
assertEquals("5yc1z", (10000007).toString(36));
assertEquals("0", (0).toString(36));
assertEquals("0", (0).toString(16));
assertEquals("0", (0).toString(10));
assertEquals("0", (0).toString(8));
assertEquals("0", (0).toString(2));
assertEquals("100000000000000000000000000000000", Math.pow(2,32).toString(2));
assertEquals("100000000000000000000000000000001", (Math.pow(2,32) + 1).toString(2));
assertEquals("100000000000080", (0x100000000000081).toString(16));
assertEquals("1000000000000100", (-(-'0x1000000000000081')).toString(16));
assertEquals("1000000000000000", (-(-'0x1000000000000080')).toString(16));
assertEquals("1000000000000000", (-(-'0x100000000000007F')).toString(16));
assertEquals("100000000000000000000000000000000000000000000000010000000", (0x100000000000081).toString(2));
assertEquals("-11111111111111111111111111111111", (-(Math.pow(2,32)-1)).toString(2));
assertEquals("-5yc1z", (-10000007).toString(36));
assertEquals("-100000000000000000000000000000000", (-Math.pow(2,32)).toString(2));
assertEquals("-100000000000000000000000000000001", (-(Math.pow(2,32) + 1)).toString(2));
assertEquals("-100000000000080", (-0x100000000000081).toString(16));
assertEquals("-100000000000000000000000000000000000000000000000010000000", (-0x100000000000081).toString(2));
assertEquals("1000", (1000).toString());
assertEquals("0.00001", (0.00001).toString());
assertEquals("1000000000000000100", (1000000000000000128).toString());
assertEquals("1e+21", (1000000000000000012800).toString());
assertEquals("-1e+21", (-1000000000000000012800).toString());
assertEquals("1e-7", (0.0000001).toString());
assertEquals("-1e-7", (-0.0000001).toString());
assertEquals("1.0000000000000001e+21", (1000000000000000128000).toString());
assertEquals("0.000001", (0.000001).toString());
assertEquals("1e-7", (0.0000001).toString());
assertEquals("8.8", (8.5).toString(16));
assertEquals("-8.8", (-8.5).toString(16));
assertEquals("1.1", (4/3).toString(3));
assertEquals("11.1", (13/3).toString(3));
assertEquals("0.01", (1/9).toString(3));
assertEquals("10000", (81).toString(3));
assertEquals("10000.01", (81 + 1/9).toString(3));
assertEquals("0.0212010212010212010212010212010212", (2/7).toString(3));
// ----------------------------------------------------------------------
// toFixed
assertEquals("NaN", (NaN).toFixed(2));
assertEquals("Infinity", (1/0).toFixed(2));
assertEquals("-Infinity", (-1/0).toFixed(2));
assertEquals("1.1111111111111111e+21", (1111111111111111111111).toFixed(8));
assertEquals("0.1", (0.1).toFixed(1));
assertEquals("0.10", (0.1).toFixed(2));
assertEquals("0.100", (0.1).toFixed(3));
assertEquals("0.01", (0.01).toFixed(2));
assertEquals("0.010", (0.01).toFixed(3));
assertEquals("0.0100", (0.01).toFixed(4));
assertEquals("0.00", (0.001).toFixed(2));
assertEquals("0.001", (0.001).toFixed(3));
assertEquals("0.0010", (0.001).toFixed(4));
assertEquals("1.0000", (1).toFixed(4));
assertEquals("1.0", (1).toFixed(1));
assertEquals("1", (1).toFixed(0));
assertEquals("12", (12).toFixed(0));
assertEquals("1", (1.1).toFixed(0));
assertEquals("12", (12.1).toFixed(0));
assertEquals("1", (1.12).toFixed(0));
assertEquals("12", (12.12).toFixed(0));
assertEquals("0.0000006", (0.0000006).toFixed(7));
assertEquals("0.00000006", (0.00000006).toFixed(8));
assertEquals("0.000000060", (0.00000006).toFixed(9));
assertEquals("0.0000000600", (0.00000006).toFixed(10));
assertEquals("0", (0).toFixed(0));
assertEquals("0.0", (0).toFixed(1));
assertEquals("0.00", (0).toFixed(2));
assertEquals("-1.1111111111111111e+21", (-1111111111111111111111).toFixed(8));
assertEquals("-0.1", (-0.1).toFixed(1));
assertEquals("-0.10", (-0.1).toFixed(2));
assertEquals("-0.100", (-0.1).toFixed(3));
assertEquals("-0.01", (-0.01).toFixed(2));
assertEquals("-0.010", (-0.01).toFixed(3));
assertEquals("-0.0100", (-0.01).toFixed(4));
assertEquals("-0.00", (-0.001).toFixed(2));
assertEquals("-0.001", (-0.001).toFixed(3));
assertEquals("-0.0010", (-0.001).toFixed(4));
assertEquals("-1.0000", (-1).toFixed(4));
assertEquals("-1.0", (-1).toFixed(1));
assertEquals("-1", (-1).toFixed(0));
assertEquals("-1", (-1.1).toFixed(0));
assertEquals("-12", (-12.1).toFixed(0));
assertEquals("-1", (-1.12).toFixed(0));
assertEquals("-12", (-12.12).toFixed(0));
assertEquals("-0.0000006", (-0.0000006).toFixed(7));
assertEquals("-0.00000006", (-0.00000006).toFixed(8));
assertEquals("-0.000000060", (-0.00000006).toFixed(9));
assertEquals("-0.0000000600", (-0.00000006).toFixed(10));
assertEquals("0", (-0).toFixed(0));
assertEquals("0.0", (-0).toFixed(1));
assertEquals("0.00", (-0).toFixed(2));
assertEquals("1000", (1000).toFixed());
assertEquals("0", (0.00001).toFixed());
assertEquals("0.00001", (0.00001).toFixed(5));
assertEquals("0.00000000000000000010", (0.0000000000000000001).toFixed(20));
assertEquals("0.00001000000000000", (0.00001).toFixed(17));
assertEquals("1.00000000000000000", (1).toFixed(17));
assertEquals("1000000000000000128", (1000000000000000128).toFixed());
assertEquals("100000000000000128.0", (100000000000000128).toFixed(1));
assertEquals("10000000000000128.00", (10000000000000128).toFixed(2));
assertEquals("10000000000000128.00000000000000000000", (10000000000000128).toFixed(20));
assertEquals("0", (0).toFixed());
assertEquals("-42.000", ((-42).toFixed(3)));
assertEquals("-1000000000000000128", (-1000000000000000128).toFixed());
assertEquals("-0.00000000000000000010", (-0.0000000000000000001).toFixed(20));
assertEquals("0.12312312312312299889", (0.123123123123123).toFixed(20));
// Test that we round up even when the last digit generated is even.
// dtoa does not do this in its original form.
assertEquals("1", 0.5.toFixed(0), "0.5.toFixed(0)");
assertEquals("-1", (-0.5).toFixed(0), "(-0.5).toFixed(0)");
assertEquals("1.3", 1.25.toFixed(1), "1.25.toFixed(1)");
// This is bizare, but Spidermonkey and KJS behave the same.
assertEquals("234.2040", (234.20405).toFixed(4), "234.2040.toFixed(4)");
assertEquals("234.2041", (234.2040506).toFixed(4));
// ----------------------------------------------------------------------
// toExponential
assertEquals("1e+0", (1).toExponential());
assertEquals("1.1e+1", (11).toExponential());
assertEquals("1.12e+2", (112).toExponential());
assertEquals("1e+0", (1).toExponential(0));
assertEquals("1e+1", (11).toExponential(0));
assertEquals("1e+2", (112).toExponential(0));
assertEquals("1.0e+0", (1).toExponential(1));
assertEquals("1.1e+1", (11).toExponential(1));
assertEquals("1.1e+2", (112).toExponential(1));
assertEquals("1.00e+0", (1).toExponential(2));
assertEquals("1.10e+1", (11).toExponential(2));
assertEquals("1.12e+2", (112).toExponential(2));
assertEquals("1.000e+0", (1).toExponential(3));
assertEquals("1.100e+1", (11).toExponential(3));
assertEquals("1.120e+2", (112).toExponential(3));
assertEquals("1e-1", (0.1).toExponential());
assertEquals("1.1e-1", (0.11).toExponential());
assertEquals("1.12e-1", (0.112).toExponential());
assertEquals("1e-1", (0.1).toExponential(0));
assertEquals("1e-1", (0.11).toExponential(0));
assertEquals("1e-1", (0.112).toExponential(0));
assertEquals("1.0e-1", (0.1).toExponential(1));
assertEquals("1.1e-1", (0.11).toExponential(1));
assertEquals("1.1e-1", (0.112).toExponential(1));
assertEquals("1.00e-1", (0.1).toExponential(2));
assertEquals("1.10e-1", (0.11).toExponential(2));
assertEquals("1.12e-1", (0.112).toExponential(2));
assertEquals("1.000e-1", (0.1).toExponential(3));
assertEquals("1.100e-1", (0.11).toExponential(3));
assertEquals("1.120e-1", (0.112).toExponential(3));
assertEquals("-1e+0", (-1).toExponential());
assertEquals("-1.1e+1", (-11).toExponential());
assertEquals("-1.12e+2", (-112).toExponential());
assertEquals("-1e+0", (-1).toExponential(0));
assertEquals("-1e+1", (-11).toExponential(0));
assertEquals("-1e+2", (-112).toExponential(0));
assertEquals("-1.0e+0", (-1).toExponential(1));
assertEquals("-1.1e+1", (-11).toExponential(1));
assertEquals("-1.1e+2", (-112).toExponential(1));
assertEquals("-1.00e+0", (-1).toExponential(2));
assertEquals("-1.10e+1", (-11).toExponential(2));
assertEquals("-1.12e+2", (-112).toExponential(2));
assertEquals("-1.000e+0", (-1).toExponential(3));
assertEquals("-1.100e+1", (-11).toExponential(3));
assertEquals("-1.120e+2", (-112).toExponential(3));
assertEquals("-1e-1", (-0.1).toExponential());
assertEquals("-1.1e-1", (-0.11).toExponential());
assertEquals("-1.12e-1", (-0.112).toExponential());
assertEquals("-1e-1", (-0.1).toExponential(0));
assertEquals("-1e-1", (-0.11).toExponential(0));
assertEquals("-1e-1", (-0.112).toExponential(0));
assertEquals("-1.0e-1", (-0.1).toExponential(1));
assertEquals("-1.1e-1", (-0.11).toExponential(1));
assertEquals("-1.1e-1", (-0.112).toExponential(1));
assertEquals("-1.00e-1", (-0.1).toExponential(2));
assertEquals("-1.10e-1", (-0.11).toExponential(2));
assertEquals("-1.12e-1", (-0.112).toExponential(2));
assertEquals("-1.000e-1", (-0.1).toExponential(3));
assertEquals("-1.100e-1", (-0.11).toExponential(3));
assertEquals("-1.120e-1", (-0.112).toExponential(3));
assertEquals("NaN", (NaN).toExponential(2));
assertEquals("Infinity", (Infinity).toExponential(2));
assertEquals("-Infinity", (-Infinity).toExponential(2));
assertEquals("1e+0", (1).toExponential(0));
assertEquals("0e+0", (0).toExponential());
assertEquals("0.00e+0", (0).toExponential(2));
assertEquals("1e+1", (11.2356).toExponential(0));
assertEquals("1.1236e+1", (11.2356).toExponential(4));
assertEquals("1.1236e-4", (0.000112356).toExponential(4));
assertEquals("-1.1236e-4", (-0.000112356).toExponential(4));
assertEquals("1.12356e-4", (0.000112356).toExponential());
assertEquals("-1.12356e-4", (-0.000112356).toExponential());
// ----------------------------------------------------------------------
// toPrecision
assertEquals("NaN", (NaN).toPrecision(1));
assertEquals("Infinity", (Infinity).toPrecision(2));
assertEquals("-Infinity", (-Infinity).toPrecision(2));
assertEquals("0.000555000000000000", (0.000555).toPrecision(15));
assertEquals("5.55000000000000e-7", (0.000000555).toPrecision(15));
assertEquals("-5.55000000000000e-7", (-0.000000555).toPrecision(15));
assertEquals("1e+8", (123456789).toPrecision(1));
assertEquals("123456789", (123456789).toPrecision(9));
assertEquals("1.2345679e+8", (123456789).toPrecision(8));
assertEquals("1.234568e+8", (123456789).toPrecision(7));
assertEquals("-1.234568e+8", (-123456789).toPrecision(7));
assertEquals("-1.2e-9", Number(-.0000000012345).toPrecision(2));
assertEquals("-1.2e-8", Number(-.000000012345).toPrecision(2));
assertEquals("-1.2e-7", Number(-.00000012345).toPrecision(2));
assertEquals("-0.0000012", Number(-.0000012345).toPrecision(2));
assertEquals("-0.000012", Number(-.000012345).toPrecision(2));
assertEquals("-0.00012", Number(-.00012345).toPrecision(2));
assertEquals("-0.0012", Number(-.0012345).toPrecision(2));
assertEquals("-0.012", Number(-.012345).toPrecision(2));
assertEquals("-0.12", Number(-.12345).toPrecision(2));
assertEquals("-1.2", Number(-1.2345).toPrecision(2));
assertEquals("-12", Number(-12.345).toPrecision(2));
assertEquals("-1.2e+2", Number(-123.45).toPrecision(2));
assertEquals("-1.2e+3", Number(-1234.5).toPrecision(2));
assertEquals("-1.2e+4", Number(-12345).toPrecision(2));
assertEquals("-1.235e+4", Number(-12345.67).toPrecision(4));
assertEquals("-1.234e+4", Number(-12344.67).toPrecision(4));
// Test that we round up even when the last digit generated is even.
// dtoa does not do this in its original form.
assertEquals("1.3", 1.25.toPrecision(2), "1.25.toPrecision(2)");
assertEquals("1.4", 1.35.toPrecision(2), "1.35.toPrecision(2)");

View File

@ -0,0 +1,291 @@
assertEquals("NaN", NaN.toString());
assertEquals("Infinity", (1 / 0).toString());
assertEquals("-Infinity", (-1 / 0).toString());
assertEquals("0", "0");
assertEquals("9", "9");
assertEquals("90", "90");
assertEquals("90.12", "90.12");
assertEquals("0.1", "0.1");
assertEquals("0.01", "0.01");
assertEquals("0.0123", "0.0123");
assertEquals("111111111111111110000", "111111111111111110000");
assertEquals("1.1111111111111111e+21", "1.1111111111111111e+21");
assertEquals("1.1111111111111111e+22", "1.1111111111111111e+22");
assertEquals("0.00001", "0.00001");
assertEquals("0.000001", "0.000001");
assertEquals("1e-7", "1e-7");
assertEquals("1.2e-7", "1.2e-7");
assertEquals("1.23e-7", "1.23e-7");
assertEquals("1e-8", "1e-8");
assertEquals("1.2e-8", "1.2e-8");
assertEquals("1.23e-8", "1.23e-8");
assertEquals("0", "0");
assertEquals("-9", "-9");
assertEquals("-90", "-90");
assertEquals("-90.12", "-90.12");
assertEquals("-0.1", "-0.1");
assertEquals("-0.01", "-0.01");
assertEquals("-0.0123", "-0.0123");
assertEquals("-111111111111111110000", "-111111111111111110000");
assertEquals("-1.1111111111111111e+21", "-1.1111111111111111e+21");
assertEquals("-1.1111111111111111e+22", "-1.1111111111111111e+22");
assertEquals("-0.00001", "-0.00001");
assertEquals("-0.000001", "-0.000001");
assertEquals("-1e-7", "-1e-7");
assertEquals("-1.2e-7", "-1.2e-7");
assertEquals("-1.23e-7", "-1.23e-7");
assertEquals("-1e-8", "-1e-8");
assertEquals("-1.2e-8", "-1.2e-8");
assertEquals("-1.23e-8", "-1.23e-8");
assertEquals("NaN", NaN.toString(16));
assertEquals("Infinity", (1 / 0).toString(16));
assertEquals("-Infinity", (-1 / 0).toString(16));
assertEquals("0", "0");
assertEquals("9", "9");
assertEquals("5a", "5a");
assertEquals("5a.1eb851eb852", 90.12.toString(16));
assertEquals("0.1999999999999a", 0.1.toString(16));
assertEquals("0.028f5c28f5c28f6", 0.01.toString(16));
assertEquals("0.032617c1bda511a", 0.0123.toString(16));
assertEquals("605f9f6dd18bc8000", "605f9f6dd18bc8000");
assertEquals("3c3bc3a4a2f75c0000", "3c3bc3a4a2f75c0000");
assertEquals("25a55a46e5da9a00000", "25a55a46e5da9a00000");
assertEquals("0.0000a7c5ac471b4788", 0.00001.toString(16));
assertEquals("0.000010c6f7a0b5ed8d", 0.000001.toString(16));
assertEquals("0.000001ad7f29abcaf48", 0.0000001.toString(16));
assertEquals("0.000002036565348d256", 0.00000012.toString(16));
assertEquals("0.0000021047ee22aa466", 0.000000123.toString(16));
assertEquals("0.0000002af31dc4611874", 0.00000001.toString(16));
assertEquals("0.000000338a23b87483be", 0.000000012.toString(16));
assertEquals("0.00000034d3fe36aaa0a2", 0.0000000123.toString(16));
assertEquals("0", "0");
assertEquals("-9", "-9");
assertEquals("-5a", "-5a");
assertEquals("-5a.1eb851eb852", (-90.12).toString(16));
assertEquals("-0.1999999999999a", (-0.1).toString(16));
assertEquals("-0.028f5c28f5c28f6", (-0.01).toString(16));
assertEquals("-0.032617c1bda511a", (-0.0123).toString(16));
assertEquals("-605f9f6dd18bc8000", "-605f9f6dd18bc8000");
assertEquals("-3c3bc3a4a2f75c0000", "-3c3bc3a4a2f75c0000");
assertEquals("-25a55a46e5da9a00000", "-25a55a46e5da9a00000");
assertEquals("-0.0000a7c5ac471b4788", (-0.00001).toString(16));
assertEquals("-0.000010c6f7a0b5ed8d", (-0.000001).toString(16));
assertEquals("-0.000001ad7f29abcaf48", (-0.0000001).toString(16));
assertEquals("-0.000002036565348d256", (-0.00000012).toString(16));
assertEquals("-0.0000021047ee22aa466", (-0.000000123).toString(16));
assertEquals("-0.0000002af31dc4611874", (-0.00000001).toString(16));
assertEquals("-0.000000338a23b87483be", (-0.000000012).toString(16));
assertEquals("-0.00000034d3fe36aaa0a2", (-0.0000000123).toString(16));
assertEquals("4294967296", "4294967296");
assertEquals("ffffffff", "ffffffff");
assertEquals("11111111111111111111111111111111", "11111111111111111111111111111111");
assertEquals("5yc1z", "5yc1z");
assertEquals("0", "0");
assertEquals("0", "0");
assertEquals("0", "0");
assertEquals("0", "0");
assertEquals("0", "0");
assertEquals("100000000000000000000000000000000", "100000000000000000000000000000000");
assertEquals("100000000000000000000000000000001", "100000000000000000000000000000001");
assertEquals("100000000000080", "100000000000080");
assertEquals("1000000000000100", "1");
assertEquals("1000000000000000", "1");
assertEquals("1000000000000000", "1");
assertEquals("100000000000000000000000000000000000000000000000010000000", "100000000000000000000000000000000000000000000000010000000");
assertEquals("-11111111111111111111111111111111", "-11111111111111111111111111111111");
assertEquals("-5yc1z", "-5yc1z");
assertEquals("-100000000000000000000000000000000", "-100000000000000000000000000000000");
assertEquals("-100000000000000000000000000000001", "-100000000000000000000000000000001");
assertEquals("-100000000000080", "-100000000000080");
assertEquals("-100000000000000000000000000000000000000000000000010000000", "-100000000000000000000000000000000000000000000000010000000");
assertEquals("1000", "1000");
assertEquals("0.00001", "0.00001");
assertEquals("1000000000000000100", "1000000000000000100");
assertEquals("1e+21", "1e+21");
assertEquals("-1e+21", "-1e+21");
assertEquals("1e-7", "1e-7");
assertEquals("-1e-7", "-1e-7");
assertEquals("1.0000000000000001e+21", "1.0000000000000001e+21");
assertEquals("0.000001", "0.000001");
assertEquals("1e-7", "1e-7");
assertEquals("8.8", 8.5.toString(16));
assertEquals("-8.8", (-8.5).toString(16));
assertEquals("1.1", (4 / 3).toString(3));
assertEquals("11.1", (13 / 3).toString(3));
assertEquals("0.01", (1 / 9).toString(3));
assertEquals("10000", "10000");
assertEquals("10000.01", (81 + 1 / 9).toString(3));
assertEquals("0.0212010212010212010212010212010212", (2 / 7).toString(3));
assertEquals("NaN", NaN.toFixed(2));
assertEquals("Infinity", (1 / 0).toFixed(2));
assertEquals("-Infinity", (-1 / 0).toFixed(2));
assertEquals("1.1111111111111111e+21", "1.1111111111111111e+21");
assertEquals("0.1", 0.1.toFixed(1));
assertEquals("0.10", 0.1.toFixed(2));
assertEquals("0.100", 0.1.toFixed(3));
assertEquals("0.01", 0.01.toFixed(2));
assertEquals("0.010", 0.01.toFixed(3));
assertEquals("0.0100", 0.01.toFixed(4));
assertEquals("0.00", 0.001.toFixed(2));
assertEquals("0.001", 0.001.toFixed(3));
assertEquals("0.0010", 0.001.toFixed(4));
assertEquals("1.0000", "1.0000");
assertEquals("1.0", "1.0");
assertEquals("1", "1");
assertEquals("12", "12");
assertEquals("1", "1");
assertEquals("12", "12");
assertEquals("1", "1");
assertEquals("12", "12");
assertEquals("0.0000006", 0.0000006.toFixed(7));
assertEquals("0.00000006", 0.00000006.toFixed(8));
assertEquals("0.000000060", 0.00000006.toFixed(9));
assertEquals("0.0000000600", 0.00000006.toFixed(10));
assertEquals("0", "0");
assertEquals("0.0", "0.0");
assertEquals("0.00", "0.00");
assertEquals("-1.1111111111111111e+21", "-1.1111111111111111e+21");
assertEquals("-0.1", (-0.1).toFixed(1));
assertEquals("-0.10", (-0.1).toFixed(2));
assertEquals("-0.100", (-0.1).toFixed(3));
assertEquals("-0.01", (-0.01).toFixed(2));
assertEquals("-0.010", (-0.01).toFixed(3));
assertEquals("-0.0100", (-0.01).toFixed(4));
assertEquals("-0.00", (-0.001).toFixed(2));
assertEquals("-0.001", (-0.001).toFixed(3));
assertEquals("-0.0010", (-0.001).toFixed(4));
assertEquals("-1.0000", "-1.0000");
assertEquals("-1.0", "-1.0");
assertEquals("-1", "-1");
assertEquals("-1", "-1");
assertEquals("-12", "-12");
assertEquals("-1", "-1");
assertEquals("-12", "-12");
assertEquals("-0.0000006", (-0.0000006).toFixed(7));
assertEquals("-0.00000006", (-0.00000006).toFixed(8));
assertEquals("-0.000000060", (-0.00000006).toFixed(9));
assertEquals("-0.0000000600", (-0.00000006).toFixed(10));
assertEquals("0", "0");
assertEquals("0.0", "0.0");
assertEquals("0.00", "0.00");
assertEquals("1000", "1000");
assertEquals("0", "0");
assertEquals("0.00001", 0.00001.toFixed(5));
assertEquals("0.00000000000000000010", 0.0000000000000000001.toFixed(20));
assertEquals("0.00001000000000000", 0.00001.toFixed(17));
assertEquals("1.00000000000000000", "1.00000000000000000");
assertEquals("1000000000000000128", "1000000000000000128");
assertEquals("100000000000000128.0", "100000000000000128.0");
assertEquals("10000000000000128.00", "10000000000000128.00");
assertEquals("10000000000000128.00000000000000000000", "10000000000000128.00000000000000000000");
assertEquals("0", "0");
assertEquals("-42.000", "-42.000");
assertEquals("-1000000000000000128", "-1000000000000000128");
assertEquals("-0.00000000000000000010", (-0.0000000000000000001).toFixed(20));
assertEquals("0.12312312312312299889", 0.123123123123123.toFixed(20));
assertEquals("1", "1", "0.5.toFixed(0)");
assertEquals("-1", "-1", "(-0.5).toFixed(0)");
assertEquals("1.3", 1.25.toFixed(1), "1.25.toFixed(1)");
assertEquals("234.2040", 234.20405.toFixed(4), "234.2040.toFixed(4)");
assertEquals("234.2041", 234.2040506.toFixed(4));
assertEquals("1e+0", "1e+0");
assertEquals("1.1e+1", "1.1e+1");
assertEquals("1.12e+2", "1.12e+2");
assertEquals("1e+0", "1e+0");
assertEquals("1e+1", "1e+1");
assertEquals("1e+2", "1e+2");
assertEquals("1.0e+0", "1.0e+0");
assertEquals("1.1e+1", "1.1e+1");
assertEquals("1.1e+2", "1.1e+2");
assertEquals("1.00e+0", "1.00e+0");
assertEquals("1.10e+1", "1.10e+1");
assertEquals("1.12e+2", "1.12e+2");
assertEquals("1.000e+0", "1.000e+0");
assertEquals("1.100e+1", "1.100e+1");
assertEquals("1.120e+2", "1.120e+2");
assertEquals("1e-1", "1e-1");
assertEquals("1.1e-1", "1.1e-1");
assertEquals("1.12e-1", "1.12e-1");
assertEquals("1e-1", "1e-1");
assertEquals("1e-1", "1e-1");
assertEquals("1e-1", "1e-1");
assertEquals("1.0e-1", "1.0e-1");
assertEquals("1.1e-1", "1.1e-1");
assertEquals("1.1e-1", "1.1e-1");
assertEquals("1.00e-1", "1.00e-1");
assertEquals("1.10e-1", "1.10e-1");
assertEquals("1.12e-1", "1.12e-1");
assertEquals("1.000e-1", "1.000e-1");
assertEquals("1.100e-1", "1.100e-1");
assertEquals("1.120e-1", "1.120e-1");
assertEquals("-1e+0", "-1e+0");
assertEquals("-1.1e+1", "-1.1e+1");
assertEquals("-1.12e+2", "-1.12e+2");
assertEquals("-1e+0", "-1e+0");
assertEquals("-1e+1", "-1e+1");
assertEquals("-1e+2", "-1e+2");
assertEquals("-1.0e+0", "-1.0e+0");
assertEquals("-1.1e+1", "-1.1e+1");
assertEquals("-1.1e+2", "-1.1e+2");
assertEquals("-1.00e+0", "-1.00e+0");
assertEquals("-1.10e+1", "-1.10e+1");
assertEquals("-1.12e+2", "-1.12e+2");
assertEquals("-1.000e+0", "-1.000e+0");
assertEquals("-1.100e+1", "-1.100e+1");
assertEquals("-1.120e+2", "-1.120e+2");
assertEquals("-1e-1", "-1e-1");
assertEquals("-1.1e-1", "-1.1e-1");
assertEquals("-1.12e-1", "-1.12e-1");
assertEquals("-1e-1", "-1e-1");
assertEquals("-1e-1", "-1e-1");
assertEquals("-1e-1", "-1e-1");
assertEquals("-1.0e-1", "-1.0e-1");
assertEquals("-1.1e-1", "-1.1e-1");
assertEquals("-1.1e-1", "-1.1e-1");
assertEquals("-1.00e-1", "-1.00e-1");
assertEquals("-1.10e-1", "-1.10e-1");
assertEquals("-1.12e-1", "-1.12e-1");
assertEquals("-1.000e-1", "-1.000e-1");
assertEquals("-1.100e-1", "-1.100e-1");
assertEquals("-1.120e-1", "-1.120e-1");
assertEquals("NaN", NaN.toExponential(2));
assertEquals("Infinity", (1 / 0).toExponential(2));
assertEquals("-Infinity", (-1 / 0).toExponential(2));
assertEquals("1e+0", "1e+0");
assertEquals("0e+0", "0e+0");
assertEquals("0.00e+0", "0.00e+0");
assertEquals("1e+1", "1e+1");
assertEquals("1.1236e+1", "1.1236e+1");
assertEquals("1.1236e-4", "1.1236e-4");
assertEquals("-1.1236e-4", "-1.1236e-4");
assertEquals("1.12356e-4", "1.12356e-4");
assertEquals("-1.12356e-4", "-1.12356e-4");
assertEquals("NaN", NaN.toPrecision(1));
assertEquals("Infinity", (1 / 0).toPrecision(2));
assertEquals("-Infinity", (-1 / 0).toPrecision(2));
assertEquals("0.000555000000000000", "0.000555000000000000");
assertEquals("5.55000000000000e-7", "5.55000000000000e-7");
assertEquals("-5.55000000000000e-7", "-5.55000000000000e-7");
assertEquals("1e+8", "1e+8");
assertEquals("123456789", "123456789");
assertEquals("1.2345679e+8", "1.2345679e+8");
assertEquals("1.234568e+8", "1.234568e+8");
assertEquals("-1.234568e+8", "-1.234568e+8");
assertEquals("-1.2e-9", Number(-0.0000000012345).toPrecision(2));
assertEquals("-1.2e-8", Number(-0.000000012345).toPrecision(2));
assertEquals("-1.2e-7", Number(-0.00000012345).toPrecision(2));
assertEquals("-0.0000012", Number(-0.0000012345).toPrecision(2));
assertEquals("-0.000012", Number(-0.000012345).toPrecision(2));
assertEquals("-0.00012", Number(-0.00012345).toPrecision(2));
assertEquals("-0.0012", Number(-0.0012345).toPrecision(2));
assertEquals("-0.012", Number(-0.012345).toPrecision(2));
assertEquals("-0.12", Number(-0.12345).toPrecision(2));
assertEquals("-1.2", Number(-1.2345).toPrecision(2));
assertEquals("-12", Number(-12.345).toPrecision(2));
assertEquals("-1.2e+2", Number(-123.45).toPrecision(2));
assertEquals("-1.2e+3", Number(-1234.5).toPrecision(2));
assertEquals("-1.2e+4", Number(-12345).toPrecision(2));
assertEquals("-1.235e+4", Number(-12345.67).toPrecision(4));
assertEquals("-1.234e+4", Number(-12344.67).toPrecision(4));
assertEquals("1.3", "1.3", "1.25.toPrecision(2)");
assertEquals("1.4", "1.4", "1.35.toPrecision(2)");

View File

@ -2,4 +2,4 @@ console.log("A");
console.log(7);
console.log(0.32999315767856785);
console.log(1.2543732512566947);
console.log("1.609398451447204");
console.log(1.6093984514472044.toFixed(15));

View File

@ -944,6 +944,13 @@ impl Fixer<'_> {
_ => self.wrap(callee),
},
Expr::Member(MemberExpr { obj, .. }) => match &**obj {
Expr::Lit(Lit::Num(num)) if num.value.signum() == -1. => {
self.wrap(obj);
}
_ => {}
},
_ => {}
}
}