From 4dbdac9c312320770f8a24a3eda6e09aa429e3c0 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Mon, 30 Dec 2019 22:41:11 +0800 Subject: [PATCH] enhance `booleans` (#3657) --- lib/compress.js | 45 ++++++++++++++++++++++++++++++-------- test/compress/booleans.js | 24 ++++++++++++++++++++ test/compress/functions.js | 4 ++-- test/compress/loops.js | 32 +++++++++++++-------------- 4 files changed, 78 insertions(+), 27 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 9c60d0ae..4252c58e 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -241,7 +241,7 @@ merge(Compressor.prototype, { return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string(); }); - AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) { + AST_Scope.DEFMETHOD("process_expression", function(insert, transform) { var self = this; var tt = new TreeTransformer(function(node) { if (insert && node instanceof AST_SimpleStatement) { @@ -250,13 +250,7 @@ merge(Compressor.prototype, { }); } if (!insert && node instanceof AST_Return) { - if (compressor) { - var value = node.value && node.value.drop_side_effect_free(compressor, true); - return value ? make_node(AST_SimpleStatement, node, { - body: value - }) : make_node(AST_EmptyStatement, node); - } - return make_node(AST_SimpleStatement, node, { + return transform ? transform(node) : make_node(AST_SimpleStatement, node, { body: node.value || make_node(AST_UnaryPrefix, node, { operator: "void", expression: make_node(AST_Number, node, { @@ -361,6 +355,7 @@ merge(Compressor.prototype, { function reset_def(tw, compressor, def) { def.assignments = 0; + def.bool_fn = 0; def.chained = false; def.cross_loop = false; def.direct_access = false; @@ -598,6 +593,7 @@ merge(Compressor.prototype, { var exp = this.expression; if (!(exp instanceof AST_SymbolRef)) return; var def = exp.definition(); + if (tw.in_boolean_context()) def.bool_fn++; if (!(def.fixed instanceof AST_Defun)) return; var defun = mark_defun(tw, def); if (!defun) return; @@ -4560,7 +4556,12 @@ merge(Compressor.prototype, { } if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) { var node = this.clone(); - exp.process_expression(false, compressor); + exp.process_expression(false, function(node) { + var value = node.value && node.value.drop_side_effect_free(compressor, true); + return value ? make_node(AST_SimpleStatement, node, { + body: value + }) : make_node(AST_EmptyStatement, node); + }); exp.walk(new TreeWalker(function(node) { if (node instanceof AST_Return && node.value) { node.value = node.value.drop_side_effect_free(compressor); @@ -6685,6 +6686,32 @@ merge(Compressor.prototype, { if (compressor.option("reduce_vars") && is_lhs(compressor.self(), parent) !== compressor.self()) { var def = self.definition(); var fixed = self.fixed_value(); + if (compressor.option("booleans") && def.bool_fn === def.references.length && fixed instanceof AST_Lambda) { + def.bool_fn = null; + fixed.process_expression(false, function(node) { + if (!node.value) return node; + var value = node.value.is_truthy() || node.value.tail_node().evaluate(compressor); + if (!value) { + value = node.value.drop_side_effect_free(compressor); + node.value = value ? make_sequence(node.value, [ + value, + make_node(AST_Number, node.value, { + value: 0 + }) + ]) : null; + } else if (value && !(value instanceof AST_Node)) { + var num = make_node(AST_Number, node.value, { + value: 1 + }); + value = node.value.drop_side_effect_free(compressor); + node.value = value ? make_sequence(node.value, [ + value, + num + ]) : num; + } + return node; + }); + } var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor)); if (single_use && fixed instanceof AST_Lambda) { if (def.scope !== self.scope diff --git a/test/compress/booleans.js b/test/compress/booleans.js index 9b8c1664..a036a1d0 100644 --- a/test/compress/booleans.js +++ b/test/compress/booleans.js @@ -86,3 +86,27 @@ issue_3465_3: { } expect_stdout: "PASS" } + +issue_2737_2: { + options = { + booleans: true, + inline: true, + reduce_vars: true, + unused: true, + } + input: { + (function(bar) { + for (;bar();) break; + })(function qux() { + return console.log("PASS"), qux; + }); + } + expect: { + (function(bar) { + for (;bar();) break; + })(function() { + return console.log("PASS"), 1; + }); + } + expect_stdout: "PASS" +} diff --git a/test/compress/functions.js b/test/compress/functions.js index 4fea42dc..30569847 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -1911,14 +1911,14 @@ issue_2737_2: { } input: { (function(bar) { - for (;bar(); ) break; + for (;bar();) break; })(function qux() { return console.log("PASS"), qux; }); } expect: { (function(bar) { - for (;bar(); ) break; + for (;bar();) break; })(function qux() { return console.log("PASS"), qux; }); diff --git a/test/compress/loops.js b/test/compress/loops.js index db0fbb9a..44874479 100644 --- a/test/compress/loops.js +++ b/test/compress/loops.js @@ -6,7 +6,7 @@ while_becomes_for: { while (foo()) bar(); } expect: { - for (; foo(); ) bar(); + for (;foo();) bar(); } } @@ -19,7 +19,7 @@ drop_if_break_1: { if (foo()) break; } expect: { - for (; !foo();); + for (;!foo();); } } @@ -32,7 +32,7 @@ drop_if_break_2: { if (foo()) break; } expect: { - for (; bar() && !foo();); + for (;bar() && !foo();); } } @@ -70,7 +70,7 @@ drop_if_break_4: { } } expect: { - for (; bar() && (x(), y(), !foo());) z(), k(); + for (;bar() && (x(), y(), !foo());) z(), k(); } } @@ -82,7 +82,7 @@ drop_if_else_break_1: { for (;;) if (foo()) bar(); else break; } expect: { - for (; foo(); ) bar(); + for (;foo();) bar(); } } @@ -97,7 +97,7 @@ drop_if_else_break_2: { } } expect: { - for (; bar() && foo();) baz(); + for (;bar() && foo();) baz(); } } @@ -114,7 +114,7 @@ drop_if_else_break_3: { } } expect: { - for (; bar() && foo();) { + for (;bar() && foo();) { baz(); stuff1(); stuff2(); @@ -138,7 +138,7 @@ drop_if_else_break_4: { } } expect: { - for (; bar() && (x(), y(), foo());) baz(), z(), k(); + for (;bar() && (x(), y(), foo());) baz(), z(), k(); } } @@ -523,13 +523,13 @@ issue_2740_1: { loops: true, } input: { - for (; ; ) break; - for (a(); ; ) break; - for (; b(); ) break; - for (c(); d(); ) break; - for (; ; e()) break; - for (f(); ; g()) break; - for (; h(); i()) break; + for (;;) break; + for (a();;) break; + for (;b();) break; + for (c(); d();) break; + for (;;e()) break; + for (f();; g()) break; + for (;h(); i()) break; for (j(); k(); l()) break; } expect: { @@ -670,7 +670,7 @@ issue_3371: { function a() { console.log("PASS"); } - for (; a(); ); + for (;a();); })(); } expect_stdout: "PASS" -- 2.34.1