enhance assignments, booleans & conditionals (#5691)

This commit is contained in:
Alex Lam S.L
2022-10-03 01:01:23 +01:00
committed by GitHub
parent 6cdc035b2f
commit 80fc862547
6 changed files with 164 additions and 58 deletions

View File

@@ -11589,12 +11589,18 @@ Compressor.prototype.compress = function(node) {
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) {
if (node instanceof AST_Dot) return repeatable(compressor, node.expression);
if (node instanceof AST_Sub) {
return repeatable(compressor, node.expression) && repeatable(compressor, node.property);
}
if (node instanceof AST_Symbol) return true;
return !node.has_side_effects(compressor);
}
@@ -11631,31 +11637,32 @@ Compressor.prototype.compress = function(node) {
if (seq !== self) return seq.optimize(compressor);
}
if (compressor.option("assignments") && lazy_op[self.operator]) {
var lhs = extract_lhs(self.left);
var right = self.right;
// a || (a = x) ---> a = a || x
// a && (a = x) ---> a = a && x
if (self.left instanceof AST_SymbolRef
// (a = x) && (a = y) ---> a = (a = x) && y
if (lhs instanceof AST_SymbolRef
&& right instanceof AST_Assign
&& right.operator == "="
&& self.left.equals(right.left)) {
var left = right.left.clone();
&& lhs.equals(right.left)) {
lhs = lhs.clone();
var assign = make_node(AST_Assign, self, {
operator: "=",
left: left,
left: lhs,
right: make_node(AST_Binary, self, {
operator: self.operator,
left: self.left,
right: right.right,
}),
});
if (left.fixed) {
left.fixed = function() {
if (lhs.fixed) {
lhs.fixed = function() {
return assign.right;
};
left.fixed.assigns = [ assign ];
lhs.fixed.assigns = [ assign ];
}
var def = left.definition();
def.references.push(left);
var def = lhs.definition();
def.references.push(lhs);
def.replaced++;
return assign.optimize(compressor);
}
@@ -11710,31 +11717,32 @@ Compressor.prototype.compress = function(node) {
case "||":
// void 0 !== x && null !== x ---> null != x
// void 0 === x || null === x ---> null == x
var lhs = self.left;
if (lhs.operator == self.operator) lhs = lhs.right;
var expr = lhs.right;
if (expr instanceof AST_Assign && expr.operator == "=") expr = expr.left;
if (lhs instanceof AST_Binary
&& lhs.operator == (self.operator == "&&" ? "!==" : "===")
&& self.right instanceof AST_Binary
&& lhs.operator == self.right.operator
&& (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null
|| 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;
var left = self.left;
if (!(left instanceof AST_Binary)) break;
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.has_side_effects(compressor)) break;
if (!expr.equals(self.right.right)) break;
left.operator = left.operator.slice(0, -1);
left.left = make_node(AST_Null, self);
return left;
}
break;
}
var in_bool = false;
var parent = compressor.parent();
if (compressor.option("booleans")) {
var lhs = self.left;
var lhs = extract_lhs(self.left);
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
// a || a ---> a
// (a = x) && a --> a = x
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);
}
@@ -11782,13 +11790,22 @@ Compressor.prototype.compress = function(node) {
case ">=": reverse("<="); break;
}
}
// x && (y && z) ---> x && y && z
// x || (y || z) ---> x || y || z
if (compressor.option("conditionals")
&& lazy_op[self.operator]
&& self.right instanceof AST_Binary
&& self.operator == self.right.operator) {
swap_chain(self, compressor);
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
if (self.right instanceof AST_Binary && self.operator == self.right.operator) swap_chain(self, compressor);
}
if (compressor.option("strings") && self.operator == "+") {
// "foo" + 42 + "" ---> "foo" + 42
@@ -12881,15 +12898,16 @@ Compressor.prototype.compress = function(node) {
}
var consequent = self.consequent;
var alternative = self.alternative;
if (repeatable(compressor, condition)) {
var cond_lhs = extract_lhs(condition);
if (repeatable(compressor, cond_lhs)) {
// 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: "||",
left: condition,
right: alternative,
}).optimize(compressor);
// 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: "&&",
left: condition,
right: consequent,