enhance `conditionals` & `switches` (#4058)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 20 Aug 2020 16:35:39 +0000 (17:35 +0100)
committerGitHub <noreply@github.com>
Thu, 20 Aug 2020 16:35:39 +0000 (00:35 +0800)
lib/compress.js
test/compress/reduce_vars.js
test/compress/switch.js

index c9892ce..8bc8b37 100644 (file)
@@ -5916,28 +5916,57 @@ merge(Compressor.prototype, {
         }
         body[0].body = decl.concat(body[0].body);
         self.body = body;
-        if (body.length == 1 && (body[0] === exact_match || body[0] === default_branch)) {
-            var has_break = false;
-            var tw = new TreeWalker(function(node) {
-                if (has_break
-                    || node instanceof AST_Lambda
-                    || node instanceof AST_SimpleStatement) return true;
-                if (is_break(node, tw)) has_break = true;
+        if (compressor.option("conditionals")) switch (body.length) {
+          case 1:
+            if (!no_break(self)) break;
+            var exp = body[0].expression;
+            var statements = body[0].body.slice();
+            if (body[0] !== default_branch && body[0] !== exact_match) return make_node(AST_If, self, {
+                condition: make_node(AST_Binary, self, {
+                    operator: "===",
+                    left: self.expression,
+                    right: exp,
+                }),
+                body: make_node(AST_BlockStatement, self, {
+                    body: statements,
+                }),
+                alternative: null,
+            }).optimize(compressor);
+            if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, {
+                body: exp,
+            }));
+            statements.unshift(make_node(AST_SimpleStatement, self.expression, {
+                body:self.expression,
+            }));
+            return make_node(AST_BlockStatement, self, {
+                body: statements,
+            }).optimize(compressor);
+          case 2:
+            if (!member(default_branch, body)) break;
+            var statements = body[0].body.slice();
+            var exclusive = statements.length && is_break(statements[statements.length - 1], compressor);
+            if (exclusive) statements.pop();
+            if (!all(statements, no_break)) break;
+            var alternative = body[1].body.length && make_node(AST_BlockStatement, body[1], body[1]);
+            var node = make_node(AST_If, self, {
+                condition: make_node(AST_Binary, self, body[0] === default_branch ? {
+                    operator: "!==",
+                    left: self.expression,
+                    right: body[1].expression,
+                } : {
+                    operator: "===",
+                    left: self.expression,
+                    right: body[0].expression,
+                }),
+                body: make_node(AST_BlockStatement, body[0], {
+                    body: statements,
+                }),
+                alternative: exclusive && alternative || null,
             });
-            self.walk(tw);
-            if (!has_break) {
-                var statements = body[0].body.slice();
-                var exp = body[0].expression;
-                if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, {
-                    body: exp
-                }));
-                statements.unshift(make_node(AST_SimpleStatement, self.expression, {
-                    body:self.expression
-                }));
-                return make_node(AST_BlockStatement, self, {
-                    body: statements
-                }).optimize(compressor);
-            }
+            if (!exclusive && alternative) node = make_node(AST_BlockStatement, self, {
+                body: [ node, alternative ],
+            });
+            return node.optimize(compressor);
         }
         return self;
 
@@ -5945,6 +5974,18 @@ merge(Compressor.prototype, {
             return node instanceof AST_Break && tw.loopcontrol_target(node) === self;
         }
 
+        function no_break(node) {
+            var found = false;
+            var tw = new TreeWalker(function(node) {
+                if (found
+                    || node instanceof AST_Lambda
+                    || node instanceof AST_SimpleStatement) return true;
+                if (is_break(node, tw)) found = true;
+            });
+            node.walk(tw);
+            return !found;
+        }
+
         function eliminate_branch(branch, prev) {
             if (prev && !aborts(prev)) {
                 prev.body = prev.body.concat(branch.body);
index 77782cf..8ed827a 100644 (file)
@@ -2031,6 +2031,7 @@ issue_1670_4: {
 
 issue_1670_5: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         keep_fargs: false,
@@ -2062,6 +2063,7 @@ issue_1670_5: {
 
 issue_1670_6: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         keep_fargs: false,
index 1de676e..83bc40f 100644 (file)
@@ -1,5 +1,6 @@
 constant_switch_1: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -19,6 +20,7 @@ constant_switch_1: {
 
 constant_switch_2: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -39,6 +41,7 @@ constant_switch_2: {
 
 constant_switch_3: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -60,6 +63,7 @@ constant_switch_3: {
 
 constant_switch_4: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -86,6 +90,7 @@ constant_switch_4: {
 
 constant_switch_5: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -120,6 +125,7 @@ constant_switch_5: {
 
 constant_switch_6: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -154,6 +160,7 @@ constant_switch_6: {
 
 constant_switch_7: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -197,6 +204,7 @@ constant_switch_7: {
 
 constant_switch_8: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -226,6 +234,7 @@ constant_switch_8: {
 
 constant_switch_9: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -315,6 +324,7 @@ keep_default: {
 
 issue_1663: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -551,6 +561,7 @@ issue_441_2: {
 
 issue_1674: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         side_effects: true,
@@ -876,6 +887,7 @@ beautify: {
 
 issue_1758: {
     options = {
+        conditionals: true,
         dead_code: true,
         switches: true,
     }
@@ -898,15 +910,16 @@ issue_1758: {
 
 issue_2535: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         switches: true,
     }
     input: {
         switch(w(), 42) {
-            case 13: x();
-            case 42: y();
-            default: z();
+          case 13: x();
+          case 42: y();
+          default: z();
         }
     }
     expect: {
@@ -919,6 +932,7 @@ issue_2535: {
 
 issue_1750: {
     options = {
+        conditionals: true,
         dead_code: true,
         evaluate: true,
         switches: true,
@@ -963,6 +977,7 @@ drop_switch_1: {
 
 drop_switch_2: {
     options = {
+        conditionals: true,
         dead_code: true,
         switches: true,
     }
@@ -1007,6 +1022,7 @@ drop_switch_3: {
 
 drop_switch_4: {
     options = {
+        conditionals: true,
         dead_code: true,
         switches: true,
     }
@@ -1028,3 +1044,109 @@ drop_switch_4: {
     }
     expect_stdout: "PASS"
 }
+
+drop_switch_5: {
+    options = {
+        conditionals: true,
+        dead_code: true,
+        switches: true,
+    }
+    input: {
+        switch (A) {
+          case B:
+            x();
+          default:
+        }
+        switch (C) {
+          default:
+            y();
+          case D:
+        }
+    }
+    expect: {
+        A === B && x();
+        C !== D && y();
+    }
+}
+
+drop_switch_6: {
+    options = {
+        conditionals: true,
+        dead_code: true,
+        switches: true,
+    }
+    input: {
+        switch (A) {
+          case B:
+          default:
+            x();
+        }
+        switch (C) {
+          default:
+          case D:
+            y();
+        }
+    }
+    expect: {
+        A === B;
+        x();
+        C !== D;
+        y();
+    }
+}
+
+drop_switch_7: {
+    options = {
+        conditionals: true,
+        dead_code: true,
+        switches: true,
+    }
+    input: {
+        switch (A) {
+          case B:
+            w();
+          default:
+            x();
+        }
+        switch (C) {
+          default:
+            y();
+          case D:
+            z();
+        }
+    }
+    expect: {
+        A === B && w();
+        x();
+        C !== D && y();
+        z();
+    }
+}
+
+drop_switch_8: {
+    options = {
+        conditionals: true,
+        dead_code: true,
+        switches: true,
+    }
+    input: {
+        switch (A) {
+          case B:
+            w();
+            break;
+          default:
+            x();
+        }
+        switch (C) {
+          default:
+            y();
+            break;
+          case D:
+            z();
+        }
+    }
+    expect: {
+        (A === B ? w : x)();
+        (C !== D ? y : z)();
+    }
+}