From 500e31e03b69d3c6fa219a74f9131c2abc9c9730 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Mon, 2 Dec 2019 15:25:38 +0800 Subject: [PATCH] enhance `collapse_vars` (#3621) --- lib/compress.js | 93 ++++++++++++++++++++++++++-------- test/compress/collapse_vars.js | 17 +++++++ 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 2c60a9b6bb..e18fd5757e 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1124,7 +1124,7 @@ merge(Compressor.prototype, { hit_index++; if (hit_index < hit_stack.length) return handle_custom_scan_order(node); hit = true; - stop_after = find_stop(node, 0); + stop_after = (value_def ? find_stop_value : find_stop)(node, 0); if (stop_after === node) abort = true; return node; } @@ -1540,46 +1540,95 @@ merge(Compressor.prototype, { function find_stop(node, level) { var parent = scanner.parent(level); - if (parent instanceof AST_Array) return value_def ? find_stop(parent, level + 1) : node; + if (parent instanceof AST_Array) return node; + if (parent instanceof AST_Assign) return node; + if (parent instanceof AST_Binary) return node; + if (parent instanceof AST_Call) return node; + if (parent instanceof AST_Case) return node; + if (parent instanceof AST_Conditional) return node; + if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Exit) return node; + if (parent instanceof AST_If) return node; + if (parent instanceof AST_IterationStatement) return node; + if (parent instanceof AST_ObjectKeyVal) return node; + if (parent instanceof AST_PropAccess) return node; + if (parent instanceof AST_Sequence) { + return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1); + } + if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Switch) return node; + if (parent instanceof AST_Unary) return node; + if (parent instanceof AST_VarDef) return node; + return null; + } + + function find_stop_value(node, level) { + var parent = scanner.parent(level); + if (parent instanceof AST_Array) return find_stop_value(parent, level + 1); if (parent instanceof AST_Assign) { - if (!value_def) return node; - if (lhs.equivalent_to(parent.left)) return node; - if (get_rvalue(candidate).equivalent_to(parent.left)) return node; - return find_stop(parent, level + 1); + if (parent.left instanceof AST_SymbolRef) { + var name = parent.left.name; + if (lhs.name == name) return node; + if (value_def.name == name) return node; + } + return find_stop_value(parent, level + 1); } if (parent instanceof AST_Binary) { - if (!value_def) return node; if (lazy_op[parent.operator] && parent.left !== node) { var grandparent = scanner.parent(level + 1); if (!(grandparent instanceof AST_Binary)) return node; if (grandparent.operator != parent.operator) return node; } - return find_stop(parent, level + 1); + return find_stop_value(parent, level + 1); + } + if (parent instanceof AST_Call) return parent; + if (parent instanceof AST_Case) { + if (parent.expression !== node) return node; + return find_stop_value(parent, level + 1); } - if (parent instanceof AST_Call) return value_def ? parent : node; - if (parent instanceof AST_Case) return node; if (parent instanceof AST_Conditional) { - if (!value_def || parent.condition !== node) return node; - return find_stop(parent, level + 1); + if (parent.condition !== node) return node; + return find_stop_value(parent, level + 1); } if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1); - if (parent instanceof AST_Exit) return node; - if (parent instanceof AST_If) return node; - if (parent instanceof AST_IterationStatement) return node; - if (parent instanceof AST_ObjectKeyVal) { - return value_def ? find_stop(scanner.parent(level + 1), level + 2) : node; + if (parent instanceof AST_Do) return node; + if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_For) { + if (parent.init !== node && parent.condition !== node) return node; + return find_stop_value(parent, level + 1); } - if (parent instanceof AST_PropAccess) return node; + if (parent instanceof AST_ForIn) { + if (parent.init !== node) return node; + return find_stop_value(parent, level + 1); + } + if (parent instanceof AST_If) { + if (parent.condition !== node) return node; + return find_stop_value(parent, level + 1); + } + if (parent instanceof AST_ObjectKeyVal) return find_stop_value(scanner.parent(level + 1), level + 2); + if (parent instanceof AST_PropAccess) return find_stop_value(parent, level + 1); if (parent instanceof AST_Sequence) { - return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1); + return (parent.tail_node() === node ? find_stop_value : find_stop_unused)(parent, level + 1); } if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1); - if (parent instanceof AST_Switch) return node; + if (parent instanceof AST_Switch) { + if (parent.expression !== node) return node; + return find_stop_value(parent, level + 1); + } if (parent instanceof AST_Unary) { if (parent.operator == "delete") return node; - return value_def ? find_stop(parent, level + 1) : node; + return find_stop_value(parent, level + 1); + } + if (parent instanceof AST_VarDef) { + var name = parent.name.name; + if (lhs.name == name) return node; + if (value_def.name == name) return node; + return find_stop_value(parent, level + 1); + } + if (parent instanceof AST_While) { + if (parent.condition !== node) return node; + return find_stop_value(parent, level + 1); } - if (parent instanceof AST_VarDef) return node; return null; } diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 58325be1db..cc6c5f9a67 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -2578,6 +2578,23 @@ chained_3: { expect_stdout: "2" } +chained_4: { + options = { + collapse_vars: true, + } + input: { + var a = "foo", b = 42; + var b = void (b = a); + console.log(a, b); + } + expect: { + var a = "foo", b = 42; + var b = void (b = a); + console.log(a, b); + } + expect_stdout: "foo undefined" +} + boolean_binary_1: { options = { collapse_vars: true,