diff --git a/lib/ast.js b/lib/ast.js index ba1330f4..cdf75d4d 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -214,12 +214,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { clone: function(deep) { var node = this._clone(deep); if (deep) { - var refs = node.label.references; - var label = this.label; + var label = node.label; + var def = this.label; node.walk(new TreeWalker(function(node) { if (node instanceof AST_LoopControl - && node.label && node.label.thedef === label) { - refs.push(node); + && node.label && node.label.thedef === def) { + node.label.thedef = label; + label.references.push(node); } })); } diff --git a/lib/compress.js b/lib/compress.js index 14c419b2..8454a432 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2404,7 +2404,7 @@ merge(Compressor.prototype, { if (compressor.option("dead_code") && self instanceof AST_While) { var a = []; extract_declarations_from_unreachable_code(compressor, self.body, a); - return make_node(AST_BlockStatement, self, { body: a }); + return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } if (self instanceof AST_Do) { var has_loop_control = false; @@ -2413,7 +2413,8 @@ merge(Compressor.prototype, { if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self) return has_loop_control = true; }); - self.walk(tw); + var parent = compressor.parent(); + (parent instanceof AST_LabeledStatement ? parent : self).walk(tw); if (!has_loop_control) return self.body; } } @@ -2483,7 +2484,7 @@ merge(Compressor.prototype, { })); } extract_declarations_from_unreachable_code(compressor, self.body, a); - return make_node(AST_BlockStatement, self, { body: a }); + return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } if (cond !== self.condition) { cond = make_node_from_constant(cond, self.condition).transform(compressor); @@ -2735,9 +2736,9 @@ merge(Compressor.prototype, { var body = []; if (self.bcatch) extract_declarations_from_unreachable_code(compressor, self.bcatch, body); if (self.bfinally) body = body.concat(self.bfinally.body); - return body.length > 0 ? make_node(AST_BlockStatement, self, { + return make_node(AST_BlockStatement, self, { body: body - }).optimize(compressor) : make_node(AST_EmptyStatement, self); + }).optimize(compressor); } return self; }); diff --git a/lib/output.js b/lib/output.js index 9ac50c08..0731fb49 100644 --- a/lib/output.js +++ b/lib/output.js @@ -190,11 +190,7 @@ function OutputStream(options) { var might_need_space = false; var might_need_semicolon = false; var might_add_newline = 0; - var last = null; - - function last_char() { - return last.charAt(last.length - 1); - }; + var last = ""; var ensure_line_len = options.max_line_len ? function() { if (current_col > options.max_line_len) { @@ -218,10 +214,11 @@ function OutputStream(options) { function print(str) { str = String(str); var ch = str.charAt(0); + var prev = last.charAt(last.length - 1); if (might_need_semicolon) { might_need_semicolon = false; - if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { + if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") { if (options.semicolons || requireSemicolonChars(ch)) { OUTPUT += ";"; current_col++; @@ -258,7 +255,6 @@ function OutputStream(options) { } if (might_need_space) { - var prev = last_char(); if ((is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")) || (ch == "/" && ch == prev) diff --git a/test/compress/issue-1833.js b/test/compress/issue-1833.js new file mode 100644 index 00000000..e46dd046 --- /dev/null +++ b/test/compress/issue-1833.js @@ -0,0 +1,134 @@ +iife_for: { + options = { + negate_iife: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function f() { + function g() { + L: for (;;) break L; + } + g(); + } + f(); + } + expect: { + !function() { + !function() { + L: for (;;) break L; + }(); + }(); + } +} + +iife_for_in: { + options = { + negate_iife: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function f() { + function g() { + L: for (var a in x) break L; + } + g(); + } + f(); + } + expect: { + !function() { + !function() { + L: for (var a in x) break L; + }(); + }(); + } +} + +iife_do: { + options = { + negate_iife: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function f() { + function g() { + L: do { + break L; + } while (1); + } + g(); + } + f(); + } + expect: { + !function() { + !function() { + L: do { + break L; + } while (1); + }(); + }(); + } +} + +iife_while: { + options = { + negate_iife: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function f() { + function g() { + L: while (1) break L; + } + g(); + } + f(); + } + expect: { + !function() { + !function() { + L: while (1) break L; + }(); + }(); + } +} + +label_do: { + options = { + evaluate: true, + loops: true, + } + input: { + L: do { + continue L; + } while (0); + } + expect: { + L: do { + continue L; + } while (0); + } +} + +label_while: { + options = { + evaluate: true, + dead_code: true, + loops: true, + } + input: { + function f() { + L: while (0) continue L; + } + } + expect_exact: "function f(){L:;}" +}