diff --git a/lib/compress.js b/lib/compress.js index 19b7256049..b01cf71097 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -11673,7 +11673,7 @@ Compressor.prototype.compress = function(node) { OPT(AST_Sequence, function(self, compressor) { var expressions = filter_for_side_effects(); var end = expressions.length - 1; - merge_assignments(); + merge_expressions(); trim_right_for_undefined(); if (end == 0) { self = maintain_this_binding(compressor.parent(), compressor.self(), expressions[0]); @@ -11717,12 +11717,58 @@ Compressor.prototype.compress = function(node) { && node.left.definition(); } - function merge_assignments() { - for (var i = 1; i < end; i++) { + function can_reorder(op1, op2) { + return op1 == op2 || op1 == "||" && op2 == "&&"; + } + + function is_lazy(node) { + return node instanceof AST_Binary && lazy_op[node.operator]; + } + + function merge_condition(a, b) { + if (is_lazy(a) && is_lazy(b) && a.operator == b.operator + && a.left.equals(b.left) && repeatable(compressor, a.left)) { + var node = a.clone(); + node.right = make_sequence(self, [ a.right, b.right ]); + return node; + } + if (is_lazy(a) && is_lazy(a.left) && can_reorder(a.left.operator, a.operator)) { + var c = merge_condition(a.left, b); + if (c) { + a = a.clone(); + a.left = a.left.right.tail_node(); + c.right.expressions[c.right.expressions.indexOf(a.left)] = a; + return c; + } + } + if (is_lazy(b) && is_lazy(b.left) && can_reorder(b.left.operator, b.operator)) { + var d = merge_condition(a, b.left); + if (d) { + b = b.clone(); + b.left = b.left.right.tail_node(); + d.right.expressions[d.right.expressions.indexOf(b.left)] = b; + return d; + } + } + } + + function merge_expressions() { + for (var i = 1; i <= end; i++) { var prev = expressions[i - 1]; + var expr = expressions[i]; + // (a && b, a && c && d) ---> a && (b, c && d) + // (a && b && c, a && d || e) ---> a && (b && c, d || e) + if (compressor.option("conditionals")) { + var node = merge_condition(prev, expr); + if (node) { + expressions.splice(--i, 2, node); + end--; + continue; + } + } + if (i == end) break; var def = is_simple_assign(prev); if (!def) continue; - var expr = expressions[i]; if (compressor.option("conditionals")) { var cond = to_conditional_assignment(compressor, def, prev.right, expr); if (cond) { @@ -11995,6 +12041,9 @@ Compressor.prototype.compress = function(node) { } function repeatable(compressor, node) { + if (node instanceof AST_Binary && lazy_op[node.operator]) { + return repeatable(compressor, node.left) && repeatable(compressor, node.right); + } if (node instanceof AST_Dot) return repeatable(compressor, node.expression); if (node instanceof AST_Sub) { return repeatable(compressor, node.expression) && repeatable(compressor, node.property); diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index 3f09d9ee13..e35a73b4b8 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -1285,6 +1285,75 @@ extendscript_2: { ] } +common_condition_1: { + options = { + conditionals: true, + sequences: true, + } + input: { + function f(a, b) { + a && console.log("foo"); + a && b && console.log("bar"); + a && b || console.log("baz"); + } + f(false, false); + f(false, true); + f(true, false); + f(true, true); + } + expect: { + function f(a, b) { + a && (console.log("foo"), b && console.log("bar")), + a && b || console.log("baz"); + } + f(false, false), + f(false, true), + f(true, false), + f(true, true); + } + expect_stdout: [ + "baz", + "baz", + "foo", + "baz", + "foo", + "bar", + ] +} + +common_condition_2: { + options = { + conditionals: true, + sequences: true, + } + input: { + function f(a, b) { + a || console.log("foo"); + a || b || console.log("bar"); + a || b && console.log("baz"); + } + f(false, false); + f(false, true); + f(true, false); + f(true, true); + } + expect: { + function f(a, b) { + a || (console.log("foo"), b || console.log("bar"), b && console.log("baz")); + } + f(false, false), + f(false, true), + f(true, false), + f(true, true); + } + expect_stdout: [ + "foo", + "bar", + "foo", + "baz", + ] +} + issue_1154: { options = { booleans: true,