From fd6144d95baebb9eaa75b5695bd75a492479c691 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sat, 18 Apr 2020 15:32:22 +0100 Subject: [PATCH] enhance `conditionals` (#3798) --- lib/compress.js | 135 +++++++++++++++++++++++----------- test/compress/conditionals.js | 2 +- test/compress/drop-unused.js | 1 + test/compress/issue-1639.js | 6 +- 4 files changed, 100 insertions(+), 44 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 3aa9f0bc..872e2bbf 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -5222,50 +5222,53 @@ merge(Compressor.prototype, { self.body = self.alternative || make_node(AST_EmptyStatement, self); self.alternative = tmp; } - if (self.body instanceof AST_SimpleStatement - && self.alternative instanceof AST_SimpleStatement) { - return make_node(AST_SimpleStatement, self, { - body: make_node(AST_Conditional, self, { - condition : self.condition, - consequent : self.body.body, - alternative : self.alternative.body - }) - }).optimize(compressor); - } - if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { - if (self_condition_length === negated_length && !negated_is_best - && self.condition instanceof AST_Binary && self.condition.operator == "||") { - // although the code length of self.condition and negated are the same, - // negated does not require additional surrounding parentheses. - // see https://github.com/mishoo/UglifyJS2/issues/979 - negated_is_best = true; - } - if (negated_is_best) return make_node(AST_SimpleStatement, self, { - body: make_node(AST_Binary, self, { - operator : "||", - left : negated, - right : self.body.body - }).transform(compressor) - }).optimize(compressor); - return make_node(AST_SimpleStatement, self, { - body: make_node(AST_Binary, self, { - operator : "&&", - left : self.condition, - right : self.body.body - }).transform(compressor) + var body = [], var_defs = [], refs = []; + var body_exprs = sequencesize(self.body, body, var_defs, refs); + var alt_exprs = sequencesize(self.alternative, body, var_defs, refs); + if (body_exprs && alt_exprs) { + if (var_defs.length > 0) body.push(make_node(AST_Var, self, { + definitions: var_defs + })); + if (body_exprs.length == 0) { + body.push(make_node(AST_SimpleStatement, self.condition, { + body: alt_exprs.length > 0 ? make_node(AST_Binary, self, { + operator : "||", + left : self.condition, + right : make_sequence(self.alternative, alt_exprs) + }).transform(compressor) : self.condition.clone() + }).optimize(compressor)); + } else if (alt_exprs.length == 0) { + if (self_condition_length === negated_length && !negated_is_best + && self.condition instanceof AST_Binary && self.condition.operator == "||") { + // although the code length of self.condition and negated are the same, + // negated does not require additional surrounding parentheses. + // see https://github.com/mishoo/UglifyJS2/issues/979 + negated_is_best = true; + } + body.push(make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : negated_is_best ? "||" : "&&", + left : negated_is_best ? negated : self.condition, + right : make_sequence(self.body, body_exprs) + }).transform(compressor) + }).optimize(compressor)); + } else { + body.push(make_node(AST_SimpleStatement, self, { + body: make_node(AST_Conditional, self, { + condition : self.condition, + consequent : make_sequence(self.body, body_exprs), + alternative : make_sequence(self.alternative, alt_exprs) + }) + }).optimize(compressor)); + } + refs.forEach(function(ref) { + ref.definition().references.push(ref); + }); + return make_node(AST_BlockStatement, self, { + body: body }).optimize(compressor); } if (is_empty(self.body)) { - if (is_empty(self.alternative)) return make_node(AST_SimpleStatement, self.condition, { - body: self.condition.clone() - }).optimize(compressor); - if (self.alternative instanceof AST_SimpleStatement) return make_node(AST_SimpleStatement, self, { - body: make_node(AST_Binary, self, { - operator : "||", - left : self.condition, - right : self.alternative.body - }).transform(compressor) - }).optimize(compressor); self = make_node(AST_If, self, { condition: negated, body: self.alternative, @@ -5320,6 +5323,56 @@ merge(Compressor.prototype, { } if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative); return self; + + function sequencesize(stat, defuns, var_defs, refs) { + if (stat == null) return []; + if (stat instanceof AST_BlockStatement) { + var exprs = []; + for (var i = 0; i < stat.body.length; i++) { + var line = stat.body[i]; + if (line instanceof AST_Defun) { + defuns.push(line); + } else if (line instanceof AST_EmptyStatement) { + continue; + } else if (line instanceof AST_SimpleStatement) { + if (!compressor.option("sequences") && exprs.length > 0) return; + exprs.push(line.body); + } else if (line instanceof AST_Var) { + if (!compressor.option("sequences") && exprs.length > 0) return; + line.definitions.forEach(process_var_def); + } else { + return; + } + } + return exprs; + } + if (stat instanceof AST_Defun) { + defuns.push(stat); + return []; + } + if (stat instanceof AST_EmptyStatement) return []; + if (stat instanceof AST_SimpleStatement) return [ stat.body ]; + if (stat instanceof AST_Var) { + var exprs = []; + stat.definitions.forEach(process_var_def); + return exprs; + } + + function process_var_def(var_def) { + var_defs.push(make_node(AST_VarDef, var_def, { + name: var_def.name, + value: null + })); + if (!var_def.value) return; + var ref = make_node(AST_SymbolRef, var_def.name, var_def.name); + exprs.push(make_node(AST_Assign, var_def, { + operator: "=", + left: ref, + right: var_def.value + })); + refs.push(ref); + } + } }); OPT(AST_Switch, function(self, compressor) { diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index c4ae9095..b78f7267 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -1384,7 +1384,7 @@ hoist_decl: { } expect: { var a, b; - x() ? y() : z(); + (x() ? y : z)(); } } diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index 0f4c6dc6..38f132bf 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -1173,6 +1173,7 @@ var_catch_toplevel: { x(); } catch (a) { var a; + var a; } }(); } diff --git a/test/compress/issue-1639.js b/test/compress/issue-1639.js index 1579e06e..6633eb2d 100644 --- a/test/compress/issue-1639.js +++ b/test/compress/issue-1639.js @@ -22,8 +22,10 @@ issue_1639_1: { console.log(a, b); } expect: { - for (var a = 100, b = 10, L1 = 5; --L1 > 0;) - if (--b, 0) var ignore = 0; + for (var a = 100, b = 10, L1 = 5; --L1 > 0;) { + var ignore; + --b; + } console.log(a, b); } expect_stdout: "100 6" -- 2.34.1