diff --git a/lib/compress.js b/lib/compress.js index a28df7e7..31e42d57 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -183,9 +183,18 @@ merge(Compressor.prototype, { value: val }).optimize(compressor); case "number": - return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, { - value: val - }).optimize(compressor); + if (isNaN(val)) { + return make_node(AST_NaN, orig); + } + + if ((1 / val) < 0) { + return make_node(AST_UnaryPrefix, orig, { + operator: "-", + expression: make_node(AST_Number, null, { value: -val }) + }); + } + + return make_node(AST_Number, orig, { value: val }).optimize(compressor); case "boolean": return make_node(val ? AST_True : AST_False, orig).optimize(compressor); case "undefined": @@ -542,6 +551,7 @@ merge(Compressor.prototype, { function handle_if_return(statements, compressor) { var self = compressor.self(); + var multiple_if_returns = has_multiple_if_returns(statements); var in_lambda = self instanceof AST_Lambda; var ret = []; loop: for (var i = statements.length; --i >= 0;) { @@ -579,7 +589,8 @@ merge(Compressor.prototype, { } //--- // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined; - if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) { + if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return) + && stat.body.value && !stat.alternative && in_lambda) { CHANGED = true; stat = stat.clone(); stat.alternative = ret[0] || make_node(AST_Return, stat, { @@ -671,6 +682,17 @@ merge(Compressor.prototype, { } } return ret; + + function has_multiple_if_returns(statements) { + var n = 0; + for (var i = statements.length; --i >= 0;) { + var stat = statements[i]; + if (stat instanceof AST_If && stat.body instanceof AST_Return) { + if (++n > 1) return true; + } + } + return false; + } }; function eliminate_dead_code(statements, compressor) { @@ -1051,10 +1073,7 @@ merge(Compressor.prototype, { return typeof e; case "void": return void ev(e, compressor); case "~": return ~ev(e, compressor); - case "-": - e = ev(e, compressor); - if (e === 0) throw def; - return -e; + case "-": return -ev(e, compressor); case "+": return +ev(e, compressor); } throw def; diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js new file mode 100644 index 00000000..d27582f3 --- /dev/null +++ b/test/compress/evaluate.js @@ -0,0 +1,39 @@ +negative_zero: { + options = { evaluate: true } + input: { + console.log( + -"", + - -"", + 1 / (-0), + 1 / (-"") + ); + } + expect: { + console.log( + -0, + 0, + 1 / (-0), + 1 / (-0) + ); + } +} + +positive_zero: { + options = { evaluate: true } + input: { + console.log( + +"", + + -"", + 1 / (+0), + 1 / (+"") + ); + } + expect: { + console.log( + 0, + -0, + 1 / (0), + 1 / (0) + ); + } +} diff --git a/test/compress/if_return.js b/test/compress/if_return.js new file mode 100644 index 00000000..78a6e818 --- /dev/null +++ b/test/compress/if_return.js @@ -0,0 +1,207 @@ +if_return_1: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + if (x) { + return true; + } + } + } + expect: { + function f(x){if(x)return!0} + } +} + +if_return_2: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x, y) { + if (x) + return 3; + if (y) + return c(); + } + } + expect: { + function f(x,y){return x?3:y?c():void 0} + } +} + +if_return_3: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + a(); + if (x) { + b(); + return false; + } + } + } + expect: { + function f(x){if(a(),x)return b(),!1} + } +} + +if_return_4: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x, y) { + a(); + if (x) return 3; + b(); + if (y) return c(); + } + } + expect: { + function f(x,y){return a(),x?3:(b(),y?c():void 0)} + } +} + +if_return_5: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f() { + if (x) + return; + return 7; + if (y) + return j; + } + } + expect: { + function f(){if(!x)return 7} + } +} + +if_return_6: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + return x ? true : void 0; + return y; + } + } + expect: { + // suboptimal + function f(x){return!!x||void 0} + } +} + +if_return_7: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + if (x) { + return true; + } + foo(); + bar(); + } + } + expect: { + // suboptimal + function f(x){return!!x||(foo(),void bar())} + } +} + +issue_1089: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function x() { + var f = document.getElementById("fname"); + if (f.files[0].size > 12345) { + alert("alert"); + f.focus(); + return false; + } + } + } + expect: { + function x() { + var f = document.getElementById("fname"); + if (f.files[0].size > 12345) + return alert("alert"), f.focus(), !1; + } + } +}