Skip to content

Commit

Permalink
enhance collapse_vars (#3616)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed Nov 30, 2019
1 parent b866a23 commit 0593892
Show file tree
Hide file tree
Showing 2 changed files with 349 additions and 6 deletions.
28 changes: 22 additions & 6 deletions lib/compress.js
Expand Up @@ -1147,7 +1147,7 @@ merge(Compressor.prototype, {
&& (scan_lhs && lhs.equivalent_to(node)
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
abort = true;
if (!hit_rhs || !value_def) abort = true;
return node;
}
if (is_lhs(node, parent)) {
Expand Down Expand Up @@ -1541,14 +1541,27 @@ 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_Assign) return node;
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 instanceof AST_Binary) {
if (!value_def || parent.left !== node) return node;
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);
}
if (parent instanceof AST_Call) return node;
if (parent instanceof AST_Call) return value_def ? parent : node;
if (parent instanceof AST_Case) return node;
if (parent instanceof AST_Conditional) return node;
if (parent instanceof AST_Conditional) {
if (!value_def || parent.condition !== node) return node;
return find_stop(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;
Expand All @@ -1562,7 +1575,10 @@ merge(Compressor.prototype, {
}
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_Unary) {
if (parent.operator == "delete") return node;
return value_def ? find_stop(parent, level + 1) : node;
}
if (parent instanceof AST_VarDef) return node;
return null;
}
Expand Down
327 changes: 327 additions & 0 deletions test/compress/collapse_vars.js
Expand Up @@ -6965,3 +6965,330 @@ setter_side_effect: {
}
expect_stdout: "PASS"
}

substitution_assign: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
f1 = b = a;
console.log(a, b);
}
function f2(a, b) {
a = 1 + (b = a);
console.log(a, b);
}
function f3(a, b) {
b = 1 + (b = a);
console.log(a, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
}
expect: {
function f1(a, b) {
f1 = a;
console.log(a, a);
}
function f2(a, b) {
a = 1 + (b = a);
console.log(a, b);
}
function f3(a, b) {
b = 1 + (b = a);
console.log(a, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
}
expect_stdout: [
"42 42",
"43 42",
"42 43",
]
}

substitution_arithmetic: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
console.log((b = a) + a, b);
}
function f2(a, b) {
console.log(a - (b = a), b);
}
function f3(a, b) {
console.log(a / (b = a) + b, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
}
expect: {
function f1(a, b) {
console.log(a + a, a);
}
function f2(a, b) {
console.log(a - a, a);
}
function f3(a, b) {
console.log(a / a + a, a);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
}
expect_stdout: [
"84 42",
"0 42",
"43 42",
]
}

substitution_logical_1: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
console.log((b = a) && a, b);
}
function f2(a, b) {
console.log(a && (b = a), b);
}
f1(42, "foo");
f1(null, true);
f2(42, "foo");
f2(null, true);
}
expect: {
function f1(a, b) {
console.log(a && a, a);
}
function f2(a, b) {
console.log(a && (b = a), b);
}
f1(42, "foo");
f1(null, true);
f2(42, "foo");
f2(null, true);
}
expect_stdout: [
"42 42",
"null null",
"42 42",
"null true"
]
}

substitution_logical_2: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
console.log((b = a) && a && b);
}
function f2(a, b) {
console.log((b = a) && a || b);
}
function f3(a, b) {
console.log((b = a) || a && b);
}
function f4(a, b) {
console.log((b = a) || a || b);
}
f1(42, "foo");
f1(null, true);
f2(42, "foo");
f2(null, true);
f3(42, "foo");
f3(null, true);
f4(42, "foo");
f4(null, true);
}
expect: {
function f1(a, b) {
console.log(a && a && a);
}
function f2(a, b) {
console.log(a && a || a);
}
function f3(a, b) {
console.log(a || a && a);
}
function f4(a, b) {
console.log(a || a || a);
}
f1(42, "foo");
f1(null, true);
f2(42, "foo");
f2(null, true);
f3(42, "foo");
f3(null, true);
f4(42, "foo");
f4(null, true);
}
expect_stdout: [
"42",
"null",
"42",
"null",
"42",
"null",
"42",
"null",
]
}

substitution_logical_3: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
console.log(a && (b = a) && b);
}
function f2(a, b) {
console.log(a && (b = a) || b);
}
function f3(a, b) {
console.log(a || (b = a) && b);
}
function f4(a, b) {
console.log(a || (b = a) || b);
}
f1(42, "foo");
f1(null, true);
f2(42, "foo");
f2(null, true);
f3(42, "foo");
f3(null, true);
f4(42, "foo");
f4(null, true);
}
expect: {
function f1(a, b) {
console.log(a && a && a);
}
function f2(a, b) {
console.log(a && (b = a) || b);
}
function f3(a, b) {
console.log(a || a && a);
}
function f4(a, b) {
console.log(a || a || a);
}
f1(42, "foo");
f1(null, true);
f2(42, "foo");
f2(null, true);
f3(42, "foo");
f3(null, true);
f4(42, "foo");
f4(null, true);
}
expect_stdout: [
"42",
"null",
"42",
"true",
"42",
"null",
"42",
"null",
]
}

substitution_conditional: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
console.log((b = a) ? a : b, a, b);
}
function f2(a, b) {
console.log(a ? b = a : b, a, b);
}
function f3(a, b) {
console.log(a ? a : b = a, a, b);
}
f1("foo", "bar");
f1(null, true);
f2("foo", "bar");
f2(null, true);
f3("foo", "bar");
f3(null, true);
}
expect: {
function f1(a, b) {
console.log(a ? a : a, a, a);
}
function f2(a, b) {
console.log(a ? b = a : b, a, b);
}
function f3(a, b) {
console.log(a ? a : b = a, a, b);
}
f1("foo", "bar");
f1(null, true);
f2("foo", "bar");
f2(null, true);
f3("foo", "bar");
f3(null, true);
}
expect_stdout: [
"foo foo foo",
"null null null",
"foo foo foo",
"true null true",
"foo foo bar",
"null null null",
]
}

substitution_unary: {
options = {
collapse_vars: true,
}
input: {
function f1(a, b) {
console.log(typeof (b = a), a, b);
}
function f2(a, b) {
console.log(void (b = a), a, b);
}
function f3(a, b) {
console.log(delete (b = a), a, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
}
expect: {
function f1(a, b) {
console.log(typeof a, a, a);
}
function f2(a, b) {
console.log(void a, a, a);
}
function f3(a, b) {
console.log(delete (b = a), a, b);
}
f1(42, "foo");
f2(42, "foo");
f3(42, "foo");
}
expect_stdout: [
"number 42 42",
"undefined 42 42",
"true 42 42",
]
}

0 comments on commit 0593892

Please sign in to comment.