enhance `booleans` (#3657)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 30 Dec 2019 14:41:11 +0000 (22:41 +0800)
committerGitHub <noreply@github.com>
Mon, 30 Dec 2019 14:41:11 +0000 (22:41 +0800)
lib/compress.js
test/compress/booleans.js
test/compress/functions.js
test/compress/loops.js

index 9c60d0a..4252c58 100644 (file)
@@ -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
index 9b8c166..a036a1d 100644 (file)
@@ -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"
+}
index 4fea42d..3056984 100644 (file)
@@ -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;
         });
index db0fbb9..4487447 100644 (file)
@@ -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"