From: Alex Lam S.L Date: Wed, 29 Mar 2017 10:31:55 +0000 (+0800) Subject: output optimal representations of NaN & Infinity (#1723) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=09f77c7d4d37350102c36b270b553f45e706d0c8;p=UglifyJS.git output optimal representations of NaN & Infinity (#1723) - move these optimisations out from `Compressor` to `OutputStream` - fixes behaviour inconsistency when running uglified code from global or module levels due to redefinition --- diff --git a/lib/compress.js b/lib/compress.js index 3c0fc452..66a6a18b 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -413,18 +413,17 @@ merge(Compressor.prototype, { value: val }); case "number": - if (isNaN(val)) { - return make_node(AST_NaN, orig); - } - - if ((1 / val) < 0) { - return make_node(AST_UnaryPrefix, orig, { + if (isNaN(val)) return make_node(AST_NaN, orig); + if (isFinite(val)) { + return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, { operator: "-", expression: make_node(AST_Number, orig, { value: -val }) - }); + }) : make_node(AST_Number, orig, { value: val }); } - - return make_node(AST_Number, orig, { value: val }); + return val < 0 ? make_node(AST_UnaryPrefix, orig, { + operator: "-", + expression: make_node(AST_Infinity, orig) + }) : make_node(AST_Infinity, orig); case "boolean": return make_node(val ? AST_True : AST_False, orig); case "undefined": @@ -3023,7 +3022,9 @@ merge(Compressor.prototype, { } } // avoids infinite recursion of numerals - if (self.operator != "-" || !(self.expression instanceof AST_Number)) { + if (self.operator != "-" + || !(self.expression instanceof AST_Number + || self.expression instanceof AST_Infinity)) { var ev = self.evaluate(compressor); if (ev !== self) { ev = make_node_from_constant(ev, self).optimize(compressor); @@ -3455,9 +3456,9 @@ merge(Compressor.prototype, { case "undefined": return make_node(AST_Undefined, self).optimize(compressor); case "NaN": - return make_node(AST_NaN, self).optimize(compressor); + return make_node(AST_NaN, self); case "Infinity": - return make_node(AST_Infinity, self).optimize(compressor); + return make_node(AST_Infinity, self); } } if (compressor.option("evaluate") && compressor.option("reduce_vars")) { @@ -3485,14 +3486,6 @@ merge(Compressor.prototype, { return self; }); - OPT(AST_Infinity, function (self, compressor) { - return make_node(AST_Binary, self, { - operator : '/', - left : make_node(AST_Number, self, {value: 1}), - right : make_node(AST_Number, self, {value: 0}) - }); - }); - OPT(AST_Undefined, function(self, compressor){ if (compressor.option("unsafe")) { var scope = compressor.find_parent(AST_Scope); diff --git a/lib/output.js b/lib/output.js index 5c11088b..d71f6aac 100644 --- a/lib/output.js +++ b/lib/output.js @@ -592,6 +592,13 @@ function OutputStream(options) { || p instanceof AST_Call && p.expression === this; }); + PARENS([ AST_Infinity, AST_NaN ], function(output){ + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this + || p instanceof AST_Call && p.expression === this + || p instanceof AST_Unary && p.operator != "+" && p.operator != "-"; + }); + PARENS(AST_Seq, function(output){ var p = output.parent(); return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) @@ -1254,10 +1261,18 @@ function OutputStream(options) { }); DEFPRINT(AST_Hole, noop); DEFPRINT(AST_Infinity, function(self, output){ - output.print("Infinity"); + output.print("1"); + output.space(); + output.print("/"); + output.space(); + output.print("0"); }); DEFPRINT(AST_NaN, function(self, output){ - output.print("NaN"); + output.print("0"); + output.space(); + output.print("/"); + output.space(); + output.print("0"); }); DEFPRINT(AST_This, function(self, output){ output.print("this"); diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index e7ea2bb2..54d4264d 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -840,8 +840,8 @@ equality_conditionals_false: { f(0, true, 0), f(1, 2, 3), f(1, null, 3), - f(NaN), - f(NaN, "foo"); + f(0/0), + f(0/0, "foo"); } expect_stdout: true } @@ -888,8 +888,8 @@ equality_conditionals_true: { f(0, true, 0), f(1, 2, 3), f(1, null, 3), - f(NaN), - f(NaN, "foo"); + f(0/0), + f(0/0, "foo"); } expect_stdout: true } diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 7a562055..35b6b925 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -52,7 +52,7 @@ and: { a = 7; a = false; - a = NaN; + a = 0/0; a = 0; a = void 0; a = null; @@ -67,7 +67,7 @@ and: { a = 6 << condition && -4.5; a = condition && false; - a = console.log("b") && NaN; + a = console.log("b") && 0/0; a = console.log("c") && 0; a = 2 * condition && void 0; a = condition + 3 && null; @@ -149,7 +149,7 @@ or: { a = 6 << condition || -4.5; a = condition || false; - a = console.log("b") || NaN; + a = console.log("b") || 0/0; a = console.log("c") || 0; a = 2 * condition || void 0; a = condition + 3 || null; @@ -196,8 +196,8 @@ negative_zero: { console.log( -0, 0, - 1 / (-0), - 1 / (-0) + -1/0, + -1/0 ); } expect_stdout: true @@ -217,8 +217,8 @@ positive_zero: { console.log( 0, -0, - 1 / (0), - 1 / (0) + 1/0, + 1/0 ); } expect_stdout: true @@ -533,7 +533,7 @@ unsafe_array: { [1, 2, 3, a][0] + 1, 2, 3, - NaN, + 0/0, "1,21", 5, (void 0)[1] + 1 diff --git a/test/compress/issue-1105.js b/test/compress/issue-1105.js index 28f1557a..f9412165 100644 --- a/test/compress/issue-1105.js +++ b/test/compress/issue-1105.js @@ -195,11 +195,12 @@ assorted_Infinity_NaN_undefined_in_with_scope: { sequences: false, } input: { + var f = console.log; var o = { undefined : 3, NaN : 4, Infinity : 5, - } + }; if (o) { f(undefined, void 0); f(NaN, 0/0); @@ -216,25 +217,25 @@ assorted_Infinity_NaN_undefined_in_with_scope: { } } expect: { - var o = { + var f = console.log, o = { undefined : 3, NaN : 4, Infinity : 5 - } + }; if (o) { f(void 0, void 0); - f(NaN, NaN); + f(0/0, 0/0); f(1/0, 1/0); - f(-(1/0), -(1/0)); - f(NaN, NaN); + f(-1/0, -1/0); + f(0/0, 0/0); } with (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); - f(-Infinity, -(1/0)); + f(-Infinity, -1/0); f(9 + undefined, 9 + void 0); } } + expect_stdout: true } - diff --git a/test/compress/issue-597.js b/test/compress/issue-597.js index f243223a..3a501532 100644 --- a/test/compress/issue-597.js +++ b/test/compress/issue-597.js @@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: { } expect: { (1/0).toString(); - NaN.toString(); // transformation to 0/0 dropped + (0/0).toString(); } } @@ -23,3 +23,87 @@ NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: { NaN.toString(); } } + +beautify_off_1: { + options = { + evaluate: true, + } + beautify = { + beautify: false, + } + input: { + var NaN; + console.log( + null, + undefined, + Infinity, + NaN, + Infinity * undefined, + Infinity.toString(), + NaN.toString(), + (Infinity * undefined).toString() + ); + } + expect_exact: "var NaN;console.log(null,void 0,1/0,NaN,0/0,(1/0).toString(),NaN.toString(),(0/0).toString());" + expect_stdout: true +} + +beautify_off_2: { + options = { + evaluate: true, + } + beautify = { + beautify: false, + } + input: { + console.log( + null.toString(), + undefined.toString() + ); + } + expect_exact: "console.log(null.toString(),(void 0).toString());" +} + +beautify_on_1: { + options = { + evaluate: true, + } + beautify = { + beautify: true, + } + input: { + var NaN; + console.log( + null, + undefined, + Infinity, + NaN, + Infinity * undefined, + Infinity.toString(), + NaN.toString(), + (Infinity * undefined).toString() + ); + } + expect_exact: [ + "var NaN;", + "", + "console.log(null, void 0, 1 / 0, NaN, 0 / 0, (1 / 0).toString(), NaN.toString(), (0 / 0).toString());", + ] + expect_stdout: true +} + +beautify_on_2: { + options = { + evaluate: true, + } + beautify = { + beautify: true, + } + input: { + console.log( + null.toString(), + undefined.toString() + ); + } + expect_exact: "console.log(null.toString(), (void 0).toString());" +} diff --git a/test/compress/properties.js b/test/compress/properties.js index 29bdfe2a..376fb9e2 100644 --- a/test/compress/properties.js +++ b/test/compress/properties.js @@ -77,7 +77,7 @@ sub_properties: { a[3.14] = 3; a.if = 4; a["foo bar"] = 5; - a[NaN] = 6; + a[0/0] = 6; a[null] = 7; a[void 0] = 8; }