enhance `if_return` (#4097)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 10 Sep 2020 14:31:34 +0000 (15:31 +0100)
committerGitHub <noreply@github.com>
Thu, 10 Sep 2020 14:31:34 +0000 (22:31 +0800)
lib/compress.js
test/compress/if_return.js

index f744ac6..50a37a6 100644 (file)
@@ -2113,18 +2113,22 @@ merge(Compressor.prototype, {
                     eliminate_spurious_blocks(stat.body);
                     [].splice.apply(statements, [i, 1].concat(stat.body));
                     i += stat.body.length;
-                } else if (stat instanceof AST_EmptyStatement) {
-                    CHANGED = true;
-                    statements.splice(i, 1);
-                } else if (stat instanceof AST_Directive) {
-                    if (!member(stat.value, seen_dirs)) {
-                        i++;
-                        seen_dirs.push(stat.value);
-                    } else {
+                    continue;
+                }
+                if (stat instanceof AST_Directive) {
+                    if (member(stat.value, seen_dirs)) {
                         CHANGED = true;
                         statements.splice(i, 1);
+                        continue;
                     }
-                } else i++;
+                    seen_dirs.push(stat.value);
+                }
+                if (stat instanceof AST_EmptyStatement) {
+                    CHANGED = true;
+                    statements.splice(i, 1);
+                    continue;
+                }
+                i++;
             }
         }
 
@@ -2295,12 +2299,32 @@ merge(Compressor.prototype, {
                 return !value || value instanceof AST_UnaryPrefix && value.operator == "void";
             }
 
+            function is_last_statement(body, stat) {
+                var index = body.lastIndexOf(stat);
+                if (index < 0) return false;
+                while (++index < body.length) {
+                    if (!is_declaration(body[index])) return false;
+                }
+                return true;
+            }
+
+            function match_target(target) {
+                var block = self, stat, level = 0;
+                do {
+                    do {
+                        if (block === target) return true;
+                        block = compressor.parent(level++);
+                    } while (block instanceof AST_If && (stat = block));
+                } while (block instanceof AST_BlockStatement && is_last_statement(block.body, stat));
+            }
+
             function can_merge_flow(ab) {
-                if (!ab) return false;
-                var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
-                return ab instanceof AST_Return && in_lambda && is_return_void(ab.value)
-                    || ab instanceof AST_Continue && self === loop_body(lct)
-                    || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
+                if (ab instanceof AST_Return) return in_lambda && is_return_void(ab.value);
+                if (!(ab instanceof AST_LoopControl)) return false;
+                var lct = compressor.loopcontrol_target(ab);
+                if (ab instanceof AST_Continue) return match_target(loop_body(lct));
+                if (lct instanceof AST_IterationStatement) return false;
+                return match_target(lct);
             }
 
             function extract_functions() {
@@ -2327,20 +2351,14 @@ merge(Compressor.prototype, {
 
             function next_index(i) {
                 for (var j = i + 1; j < statements.length; j++) {
-                    var stat = statements[j];
-                    if (!(stat instanceof AST_Var && declarations_only(stat))) {
-                        break;
-                    }
+                    if (!is_declaration(statements[j])) break;
                 }
                 return j;
             }
 
             function prev_index(i) {
                 for (var j = i; --j >= 0;) {
-                    var stat = statements[j];
-                    if (!(stat instanceof AST_Var && declarations_only(stat))) {
-                        break;
-                    }
+                    if (!is_declaration(statements[j])) break;
                 }
                 return j;
             }
@@ -2383,6 +2401,10 @@ merge(Compressor.prototype, {
             });
         }
 
+        function is_declaration(stat) {
+            return stat instanceof AST_Defun || stat instanceof AST_Var && declarations_only(stat);
+        }
+
         function sequencesize(statements, compressor) {
             if (statements.length < 2) return;
             var seq = [], n = 0;
@@ -2399,8 +2421,7 @@ merge(Compressor.prototype, {
                     var body = stat.body;
                     if (seq.length > 0) body = body.drop_side_effect_free(compressor);
                     if (body) merge_sequence(seq, body);
-                } else if (stat instanceof AST_Definitions && declarations_only(stat)
-                    || stat instanceof AST_Defun) {
+                } else if (is_declaration(stat)) {
                     statements[n++] = stat;
                 } else {
                     push_seq();
index 836fab1..90ae121 100644 (file)
@@ -594,3 +594,72 @@ iife_if_return_simple: {
     }
     expect_stdout: "PASS"
 }
+
+nested_if_break: {
+    options = {
+        if_return: true,
+    }
+    input: {
+        for (var i = 0; i < 3; i++)
+            L1: if ("number" == typeof i) {
+                if (0 === i) break L1;
+                console.log(i);
+            }
+    }
+    expect: {
+        for (var i = 0; i < 3; i++)
+            L1: if ("number" == typeof i)
+                if (0 !== i) console.log(i);
+    }
+    expect_stdout: [
+        "1",
+        "2",
+    ]
+}
+
+nested_if_continue: {
+    options = {
+        conditionals: true,
+        if_return: true,
+        join_vars: true,
+        loops: true,
+    }
+    input: {
+        function f(n) {
+            var i = 0;
+            do {
+                if ("number" == typeof n) {
+                    if (0 === n) {
+                        console.log("even", i);
+                        continue;
+                    }
+                    if (1 === n) {
+                        console.log("odd", i);
+                        continue;
+                    }
+                    i++;
+                }
+            } while (0 <= (n -= 2));
+        }
+        f(37);
+        f(42);
+    }
+    expect: {
+        function f(n) {
+            for (var i = 0;
+                "number" == typeof n
+                    && (0 !== n
+                        ? 1 !== n
+                            ? i++
+                            : console.log("odd", i)
+                        : console.log("even", i)),
+                0 <= (n -= 2););
+        }
+        f(37);
+        f(42);
+    }
+    expect_stdout: [
+        "odd 18",
+        "even 21",
+    ]
+}