enhance assignments, booleans & conditionals (#5691)
This commit is contained in:
@@ -11589,12 +11589,18 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (node instanceof AST_Unary) return true;
|
if (node instanceof AST_Unary) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extract_lhs(node) {
|
||||||
|
if (node instanceof AST_Assign) return node.left;
|
||||||
|
if (node instanceof AST_Sequence) return extract_lhs(node.tail_node());
|
||||||
|
if (node instanceof AST_UnaryPrefix && UNARY_POSTFIX[node.operator]) return node.expression;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
function repeatable(compressor, node) {
|
function repeatable(compressor, node) {
|
||||||
if (node instanceof AST_Dot) return repeatable(compressor, node.expression);
|
if (node instanceof AST_Dot) return repeatable(compressor, node.expression);
|
||||||
if (node instanceof AST_Sub) {
|
if (node instanceof AST_Sub) {
|
||||||
return repeatable(compressor, node.expression) && repeatable(compressor, node.property);
|
return repeatable(compressor, node.expression) && repeatable(compressor, node.property);
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Symbol) return true;
|
|
||||||
return !node.has_side_effects(compressor);
|
return !node.has_side_effects(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11631,31 +11637,32 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("assignments") && lazy_op[self.operator]) {
|
if (compressor.option("assignments") && lazy_op[self.operator]) {
|
||||||
|
var lhs = extract_lhs(self.left);
|
||||||
var right = self.right;
|
var right = self.right;
|
||||||
// a || (a = x) ---> a = a || x
|
// a || (a = x) ---> a = a || x
|
||||||
// a && (a = x) ---> a = a && x
|
// (a = x) && (a = y) ---> a = (a = x) && y
|
||||||
if (self.left instanceof AST_SymbolRef
|
if (lhs instanceof AST_SymbolRef
|
||||||
&& right instanceof AST_Assign
|
&& right instanceof AST_Assign
|
||||||
&& right.operator == "="
|
&& right.operator == "="
|
||||||
&& self.left.equals(right.left)) {
|
&& lhs.equals(right.left)) {
|
||||||
var left = right.left.clone();
|
lhs = lhs.clone();
|
||||||
var assign = make_node(AST_Assign, self, {
|
var assign = make_node(AST_Assign, self, {
|
||||||
operator: "=",
|
operator: "=",
|
||||||
left: left,
|
left: lhs,
|
||||||
right: make_node(AST_Binary, self, {
|
right: make_node(AST_Binary, self, {
|
||||||
operator: self.operator,
|
operator: self.operator,
|
||||||
left: self.left,
|
left: self.left,
|
||||||
right: right.right,
|
right: right.right,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
if (left.fixed) {
|
if (lhs.fixed) {
|
||||||
left.fixed = function() {
|
lhs.fixed = function() {
|
||||||
return assign.right;
|
return assign.right;
|
||||||
};
|
};
|
||||||
left.fixed.assigns = [ assign ];
|
lhs.fixed.assigns = [ assign ];
|
||||||
}
|
}
|
||||||
var def = left.definition();
|
var def = lhs.definition();
|
||||||
def.references.push(left);
|
def.references.push(lhs);
|
||||||
def.replaced++;
|
def.replaced++;
|
||||||
return assign.optimize(compressor);
|
return assign.optimize(compressor);
|
||||||
}
|
}
|
||||||
@@ -11710,31 +11717,32 @@ Compressor.prototype.compress = function(node) {
|
|||||||
case "||":
|
case "||":
|
||||||
// void 0 !== x && null !== x ---> null != x
|
// void 0 !== x && null !== x ---> null != x
|
||||||
// void 0 === x || null === x ---> null == x
|
// void 0 === x || null === x ---> null == x
|
||||||
var lhs = self.left;
|
var left = self.left;
|
||||||
if (lhs.operator == self.operator) lhs = lhs.right;
|
if (!(left instanceof AST_Binary)) break;
|
||||||
var expr = lhs.right;
|
if (left.operator != (self.operator == "&&" ? "!==" : "===")) break;
|
||||||
|
if (!(self.right instanceof AST_Binary)) break;
|
||||||
|
if (left.operator != self.right.operator) break;
|
||||||
|
if (is_undefined(left.left, compressor) && self.right.left instanceof AST_Null
|
||||||
|
|| left.left instanceof AST_Null && is_undefined(self.right.left, compressor)) {
|
||||||
|
var expr = left.right;
|
||||||
if (expr instanceof AST_Assign && expr.operator == "=") expr = expr.left;
|
if (expr instanceof AST_Assign && expr.operator == "=") expr = expr.left;
|
||||||
if (lhs instanceof AST_Binary
|
if (expr.has_side_effects(compressor)) break;
|
||||||
&& lhs.operator == (self.operator == "&&" ? "!==" : "===")
|
if (!expr.equals(self.right.right)) break;
|
||||||
&& self.right instanceof AST_Binary
|
left.operator = left.operator.slice(0, -1);
|
||||||
&& lhs.operator == self.right.operator
|
left.left = make_node(AST_Null, self);
|
||||||
&& (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null
|
return left;
|
||||||
|| lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor))
|
|
||||||
&& !expr.has_side_effects(compressor)
|
|
||||||
&& expr.equals(self.right.right)) {
|
|
||||||
lhs.operator = lhs.operator.slice(0, -1);
|
|
||||||
lhs.left = make_node(AST_Null, self);
|
|
||||||
return self.left;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var in_bool = false;
|
var in_bool = false;
|
||||||
var parent = compressor.parent();
|
var parent = compressor.parent();
|
||||||
if (compressor.option("booleans")) {
|
if (compressor.option("booleans")) {
|
||||||
var lhs = self.left;
|
var lhs = extract_lhs(self.left);
|
||||||
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
|
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
|
||||||
|
// a || a ---> a
|
||||||
|
// (a = x) && a --> a = x
|
||||||
if (lhs.equals(self.right)) {
|
if (lhs.equals(self.right)) {
|
||||||
return maintain_this_binding(parent, compressor.self(), lhs).optimize(compressor);
|
return maintain_this_binding(parent, compressor.self(), self.left).optimize(compressor);
|
||||||
}
|
}
|
||||||
mark_duplicate_condition(compressor, lhs);
|
mark_duplicate_condition(compressor, lhs);
|
||||||
}
|
}
|
||||||
@@ -11782,13 +11790,22 @@ Compressor.prototype.compress = function(node) {
|
|||||||
case ">=": reverse("<="); break;
|
case ">=": reverse("<="); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (compressor.option("conditionals") && lazy_op[self.operator]) {
|
||||||
|
if (self.left instanceof AST_Binary && self.operator == self.left.operator) {
|
||||||
|
var before = make_node(AST_Binary, self, {
|
||||||
|
operator: self.operator,
|
||||||
|
left: self.left.right,
|
||||||
|
right: self.right,
|
||||||
|
});
|
||||||
|
var after = before.optimize(compressor);
|
||||||
|
if (before !== after) {
|
||||||
|
self.left = self.left.left;
|
||||||
|
self.right = after;
|
||||||
|
}
|
||||||
|
}
|
||||||
// x && (y && z) ---> x && y && z
|
// x && (y && z) ---> x && y && z
|
||||||
// x || (y || z) ---> x || y || z
|
// x || (y || z) ---> x || y || z
|
||||||
if (compressor.option("conditionals")
|
if (self.right instanceof AST_Binary && self.operator == self.right.operator) swap_chain(self, compressor);
|
||||||
&& lazy_op[self.operator]
|
|
||||||
&& self.right instanceof AST_Binary
|
|
||||||
&& self.operator == self.right.operator) {
|
|
||||||
swap_chain(self, compressor);
|
|
||||||
}
|
}
|
||||||
if (compressor.option("strings") && self.operator == "+") {
|
if (compressor.option("strings") && self.operator == "+") {
|
||||||
// "foo" + 42 + "" ---> "foo" + 42
|
// "foo" + 42 + "" ---> "foo" + 42
|
||||||
@@ -12881,15 +12898,16 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
var consequent = self.consequent;
|
var consequent = self.consequent;
|
||||||
var alternative = self.alternative;
|
var alternative = self.alternative;
|
||||||
if (repeatable(compressor, condition)) {
|
var cond_lhs = extract_lhs(condition);
|
||||||
|
if (repeatable(compressor, cond_lhs)) {
|
||||||
// x ? x : y ---> x || y
|
// x ? x : y ---> x || y
|
||||||
if (condition.equals(consequent)) return make_node(AST_Binary, self, {
|
if (cond_lhs.equals(consequent)) return make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: condition,
|
left: condition,
|
||||||
right: alternative,
|
right: alternative,
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
// x ? y : x ---> x && y
|
// x ? y : x ---> x && y
|
||||||
if (condition.equals(alternative)) return make_node(AST_Binary, self, {
|
if (cond_lhs.equals(alternative)) return make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: condition,
|
left: condition,
|
||||||
right: consequent,
|
right: consequent,
|
||||||
|
|||||||
@@ -290,6 +290,45 @@ increment_decrement_2: {
|
|||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazily_chained_assignments: {
|
||||||
|
options = {
|
||||||
|
assignments: true,
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
if (a = console.log("foo"))
|
||||||
|
a = console.log("bar");
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function g(b) {
|
||||||
|
if (b = console.log("baz"))
|
||||||
|
;
|
||||||
|
else
|
||||||
|
b = console.log("moo");
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(f(), g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return console.log("foo") && console.log("bar");
|
||||||
|
}
|
||||||
|
function g(b) {
|
||||||
|
return console.log("baz") || console.log("moo");
|
||||||
|
}
|
||||||
|
console.log(f(), g());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"baz",
|
||||||
|
"moo",
|
||||||
|
"undefined undefined",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
issue_3375_1: {
|
issue_3375_1: {
|
||||||
options = {
|
options = {
|
||||||
assignments: true,
|
assignments: true,
|
||||||
|
|||||||
@@ -80,6 +80,25 @@ de_morgan_1c: {
|
|||||||
expect_stdout: "true"
|
expect_stdout: "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
de_morgan_1d: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return (a = false) || a;
|
||||||
|
}
|
||||||
|
console.log(f(null), f(42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = !1;
|
||||||
|
}
|
||||||
|
console.log(f(null), f(42));
|
||||||
|
}
|
||||||
|
expect_stdout: "false false"
|
||||||
|
}
|
||||||
|
|
||||||
de_morgan_2a: {
|
de_morgan_2a: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
@@ -181,6 +200,31 @@ de_morgan_2d: {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
de_morgan_2e: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
return (a && b) && b;
|
||||||
|
}
|
||||||
|
console.log(f(null), f(null, {}));
|
||||||
|
console.log(f(42), f(42, {}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
return a && b;
|
||||||
|
}
|
||||||
|
console.log(f(null), f(null, {}));
|
||||||
|
console.log(f(42), f(42, {}));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"null null",
|
||||||
|
"undefined {}",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
de_morgan_3a: {
|
de_morgan_3a: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
|
|||||||
@@ -76,12 +76,14 @@ self_comparison_1: {
|
|||||||
comparisons: true,
|
comparisons: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
var a, b;
|
||||||
a === a;
|
a === a;
|
||||||
a !== b;
|
a !== b;
|
||||||
b.c === a.c;
|
b.c === a.c;
|
||||||
b.c !== b.c;
|
b.c !== b.c;
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var a, b;
|
||||||
a == a;
|
a == a;
|
||||||
a !== b;
|
a !== b;
|
||||||
b.c === a.c;
|
b.c === a.c;
|
||||||
@@ -275,6 +277,7 @@ issue_2857_3: {
|
|||||||
issue_2857_4: {
|
issue_2857_4: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f(a, p) {
|
function f(a, p) {
|
||||||
@@ -305,6 +308,7 @@ issue_2857_4: {
|
|||||||
issue_2857_5: {
|
issue_2857_5: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f(a, p) {
|
function f(a, p) {
|
||||||
@@ -528,6 +532,7 @@ nullish_assign: {
|
|||||||
nullish_chain: {
|
nullish_chain: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a;
|
var a;
|
||||||
|
|||||||
@@ -3028,7 +3028,7 @@ issue_5673_2: {
|
|||||||
expect: {
|
expect: {
|
||||||
var a = "PASS";
|
var a = "PASS";
|
||||||
console.log(function(b) {
|
console.log(function(b) {
|
||||||
return ((b = a) || (b = a)) && b;
|
return a || (b = a) && b;
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
|
|||||||
@@ -976,33 +976,33 @@ nested_if_return: {
|
|||||||
if_return: true,
|
if_return: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
function f(a, b, c, d, e, f, g, h, i, j, k, l, m, n) {
|
||||||
if (A) {
|
if (a) {
|
||||||
if (B)
|
if (b)
|
||||||
return B;
|
return b;
|
||||||
if (C)
|
if (c)
|
||||||
return D;
|
return d;
|
||||||
if (E)
|
if (e)
|
||||||
return F;
|
return f;
|
||||||
if (G)
|
if (g)
|
||||||
return H;
|
return h;
|
||||||
if (I) {
|
if (i) {
|
||||||
if (J)
|
if (j)
|
||||||
return K;
|
return k;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (L) {
|
if (l) {
|
||||||
if (M)
|
if (m)
|
||||||
return;
|
return;
|
||||||
return N;
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f(a, b, c, d, e, f, g, h, i, j, k, l, m, n) {
|
||||||
if (A)
|
if (a)
|
||||||
return B || (C ? D : E ? F : G ? H : I ? J ? K : void 0 : L && !M ? N : void 0);
|
return b || (c ? d : e ? f : g ? h : i ? j ? k : void 0 : l && !m ? n : void 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user