aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js28
-rw-r--r--test/compress/collapse_vars.js327
2 files changed, 349 insertions, 6 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 34700d4a..6a76fc32 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -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)) {
@@ -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;
@@ -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;
}
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 20bbfea2..75dddb02 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -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",
+ ]
+}