From b82fd0ad41983065ad6f58d9bfe4dac7720909bf Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 10 Apr 2018 06:51:03 +0800 Subject: [PATCH] handle flow control in loops with `reduce_vars` (#3069) fixes #3068 --- lib/compress.js | 72 +++++++++++++++++++++++------------- test/compress/reduce_vars.js | 56 ++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 26 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 73f46326..5323a867 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -530,11 +530,16 @@ merge(Compressor.prototype, { tw.safe_ids = save_ids; return true; }); - def(AST_DWLoop, function(tw, descend) { + def(AST_Do, function(tw) { var saved_loop = tw.in_loop; tw.in_loop = this; push(tw); - descend(); + this.body.walk(tw); + if (has_break_or_continue(this)) { + pop(tw); + push(tw); + } + this.condition.walk(tw); pop(tw); tw.in_loop = saved_loop; return true; @@ -543,19 +548,17 @@ merge(Compressor.prototype, { if (this.init) this.init.walk(tw); var saved_loop = tw.in_loop; tw.in_loop = this; - if (this.condition) { - push(tw); - this.condition.walk(tw); - pop(tw); - } push(tw); + if (this.condition) this.condition.walk(tw); this.body.walk(tw); - pop(tw); if (this.step) { - push(tw); + if (has_break_or_continue(this)) { + pop(tw); + push(tw); + } this.step.walk(tw); - pop(tw); } + pop(tw); tw.in_loop = saved_loop; return true; }); @@ -713,6 +716,15 @@ merge(Compressor.prototype, { } } }); + def(AST_While, function(tw, descend) { + var saved_loop = tw.in_loop; + tw.in_loop = this; + push(tw); + descend(); + pop(tw); + tw.in_loop = saved_loop; + return true; + }); })(function(node, func){ node.DEFMETHOD("reduce_vars", func); }); @@ -3837,6 +3849,20 @@ merge(Compressor.prototype, { return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self; }); + function has_break_or_continue(loop, parent) { + var found = false; + var tw = new TreeWalker(function(node) { + if (found || node instanceof AST_Scope) return true; + if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === loop) { + return found = true; + } + }); + if (parent instanceof AST_LabeledStatement) tw.push(parent); + tw.push(loop); + loop.body.walk(tw); + return found; + } + OPT(AST_Do, function(self, compressor){ if (!compressor.option("loops")) return self; var cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor); @@ -3851,22 +3877,16 @@ merge(Compressor.prototype, { ] }) }).optimize(compressor); - var has_loop_control = false; - var tw = new TreeWalker(function(node) { - if (node instanceof AST_Scope || has_loop_control) return true; - if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self) - return has_loop_control = true; - }); - var parent = compressor.parent(); - (parent instanceof AST_LabeledStatement ? parent : self).walk(tw); - if (!has_loop_control) return make_node(AST_BlockStatement, self.body, { - body: [ - self.body, - make_node(AST_SimpleStatement, self.condition, { - body: self.condition - }) - ] - }).optimize(compressor); + if (!has_break_or_continue(self, compressor.parent())) { + return make_node(AST_BlockStatement, self.body, { + body: [ + self.body, + make_node(AST_SimpleStatement, self.condition, { + body: self.condition + }) + ] + }).optimize(compressor); + } } if (self.body instanceof AST_SimpleStatement) return make_node(AST_For, self, { condition: make_sequence(self.condition, [ diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 59a99b9c..63a17e72 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -5654,3 +5654,59 @@ issue_3042_2: { "true", ] } + +issue_3068_1: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + (function() { + do { + continue; + var b = "defined"; + } while (b && b.c); + })(); + } + expect: { + (function() { + do { + continue; + var b = "defined"; + } while (b && b.c); + })(); + } + expect_stdout: true +} + +issue_3068_2: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + (function() { + do { + try { + while ("" == typeof a); + } finally { + continue; + } + var b = "defined"; + } while (b && b.c); + })(); + } + expect: { + (function() { + do { + try { + while ("" == typeof a); + } finally { + continue; + } + var b = "defined"; + } while (b && b.c); + })(); + } + expect_stdout: true +} -- 2.34.1