enhance conditionals (#5542)
This commit is contained in:
130
lib/compress.js
130
lib/compress.js
@@ -270,10 +270,6 @@ Compressor.prototype.compress = function(node) {
|
||||
return self;
|
||||
});
|
||||
|
||||
AST_Node.DEFMETHOD("equivalent_to", function(node) {
|
||||
return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string();
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("hoist_exports", function(compressor) {
|
||||
if (!compressor.option("hoist_exports")) return;
|
||||
var body = this.body, props = [];
|
||||
@@ -930,7 +926,7 @@ Compressor.prototype.compress = function(node) {
|
||||
var scan = ld || left instanceof AST_Destructured;
|
||||
switch (node.operator) {
|
||||
case "=":
|
||||
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
|
||||
if (left.equals(right) && !left.has_side_effects(compressor)) {
|
||||
right.walk(tw);
|
||||
walk_prop(left);
|
||||
node.redundant = true;
|
||||
@@ -2031,7 +2027,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// Cascade compound assignments
|
||||
if (compound && scan_lhs && can_replace && !stop_if_hit
|
||||
&& node instanceof AST_Assign && node.operator != "=" && node.left.equivalent_to(lhs)) {
|
||||
&& node instanceof AST_Assign && node.operator != "=" && node.left.equals(lhs)) {
|
||||
replaced++;
|
||||
changed = true;
|
||||
AST_Node.info("Cascading {node} [{file}:{line},{col}]", {
|
||||
@@ -2075,7 +2071,7 @@ Compressor.prototype.compress = function(node) {
|
||||
// Replace variable with assignment when found
|
||||
var hit_rhs;
|
||||
if (!(node instanceof AST_SymbolDeclaration)
|
||||
&& (scan_lhs && lhs.equivalent_to(node)
|
||||
&& (scan_lhs && lhs.equals(node)
|
||||
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
|
||||
if (!can_replace || stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
||||
if (!hit_rhs && !value_def) abort = true;
|
||||
@@ -2420,11 +2416,11 @@ Compressor.prototype.compress = function(node) {
|
||||
if (node !== parent.init) return true;
|
||||
}
|
||||
if (node instanceof AST_Assign) {
|
||||
return node.operator != "=" && lhs.equivalent_to(node.left);
|
||||
return node.operator != "=" && lhs.equals(node.left);
|
||||
}
|
||||
if (node instanceof AST_Call) {
|
||||
if (!(lhs instanceof AST_PropAccess)) return false;
|
||||
if (!lhs.equivalent_to(node.expression)) return false;
|
||||
if (!lhs.equals(node.expression)) return false;
|
||||
return !(rvalue instanceof AST_LambdaExpression && !rvalue.contains_this());
|
||||
}
|
||||
if (node instanceof AST_Class) return !compressor.has_directive("use strict");
|
||||
@@ -3102,7 +3098,7 @@ Compressor.prototype.compress = function(node) {
|
||||
return !circular && rhs_exact_match;
|
||||
|
||||
function rhs_exact_match(node) {
|
||||
return expr.equivalent_to(node);
|
||||
return expr.equals(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3400,7 +3396,7 @@ Compressor.prototype.compress = function(node) {
|
||||
var changed = false;
|
||||
var parent = compressor.parent();
|
||||
var self = compressor.self();
|
||||
var exit, exit_defs, merge_exit;
|
||||
var exit, merge_exit;
|
||||
var in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self;
|
||||
var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences");
|
||||
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||
@@ -3548,7 +3544,6 @@ Compressor.prototype.compress = function(node) {
|
||||
|
||||
if (stat instanceof AST_Exit) {
|
||||
exit = stat;
|
||||
exit_defs = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3578,30 +3573,15 @@ Compressor.prototype.compress = function(node) {
|
||||
if (exit.TYPE != ab.TYPE) return false;
|
||||
var value = ab.value;
|
||||
if (!value) return false;
|
||||
var equals = exit.equivalent_to(ab);
|
||||
var equals = exit.equals(ab);
|
||||
if (!equals && value instanceof AST_Sequence) {
|
||||
value = value.tail_node();
|
||||
if (exit.value && exit.value.equivalent_to(value)) equals = 2;
|
||||
if (exit.value && exit.value.equals(value)) equals = 2;
|
||||
}
|
||||
if (!equals && !exact && exit.value instanceof AST_Sequence) {
|
||||
if (exit.value.tail_node().equivalent_to(value)) equals = 3;
|
||||
if (exit.value.tail_node().equals(value)) equals = 3;
|
||||
}
|
||||
if (!equals) return false;
|
||||
if (exit_defs == null) {
|
||||
exit_defs = new Dictionary();
|
||||
exit.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_SymbolRef) exit_defs.set(node.name, node.definition());
|
||||
}));
|
||||
if (!exit_defs.size()) exit_defs = false;
|
||||
}
|
||||
var abort = false;
|
||||
if (exit_defs) value.walk(new TreeWalker(function(node) {
|
||||
if (abort) return true;
|
||||
if (node instanceof AST_SymbolRef && exit_defs.get(node.name) !== node.definition()) {
|
||||
return abort = true;
|
||||
}
|
||||
}));
|
||||
return !abort && equals;
|
||||
return equals;
|
||||
}
|
||||
|
||||
function can_drop_abort(ab) {
|
||||
@@ -4635,7 +4615,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (keep_unary
|
||||
&& fixed instanceof AST_UnaryPrefix
|
||||
&& fixed.operator == "+"
|
||||
&& fixed.expression.equivalent_to(this)) {
|
||||
&& fixed.expression.equals(this)) {
|
||||
return false;
|
||||
}
|
||||
this.is_number = return_false;
|
||||
@@ -9456,10 +9436,10 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
|
||||
function match(cond) {
|
||||
if (node.equivalent_to(cond)) return true;
|
||||
if (node.equals(cond)) return true;
|
||||
if (!(cond instanceof AST_UnaryPrefix)) return false;
|
||||
if (cond.operator != "!") return false;
|
||||
if (!node.equivalent_to(cond.expression)) return false;
|
||||
if (!node.equals(cond.expression)) return false;
|
||||
negated = true;
|
||||
return true;
|
||||
}
|
||||
@@ -9633,9 +9613,43 @@ Compressor.prototype.compress = function(node) {
|
||||
self.alternative = null;
|
||||
return make_node(AST_BlockStatement, self, { body: [ self, body ] }).optimize(compressor);
|
||||
}
|
||||
if (self.alternative) {
|
||||
var body_stats = as_array(self.body);
|
||||
var body_index = last_index(body_stats);
|
||||
var alt_stats = as_array(self.alternative);
|
||||
var alt_index = last_index(alt_stats);
|
||||
for (var stats = []; body_index >= 0 && alt_index >= 0;) {
|
||||
var stat = body_stats[body_index];
|
||||
if (!stat.equals(alt_stats[alt_index])) break;
|
||||
body_stats.splice(body_index--, 1);
|
||||
alt_stats.splice(alt_index--, 1);
|
||||
stats.unshift(stat);
|
||||
}
|
||||
if (stats.length > 0) {
|
||||
self.body = body_stats.length > 0 ? make_node(AST_BlockStatement, self, {
|
||||
body: body_stats,
|
||||
}) : make_node(AST_EmptyStatement, self);
|
||||
self.alternative = alt_stats.length > 0 ? make_node(AST_BlockStatement, self, {
|
||||
body: alt_stats,
|
||||
}) : null;
|
||||
stats.unshift(self);
|
||||
return make_node(AST_BlockStatement, self, { body: stats }).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative);
|
||||
return self;
|
||||
|
||||
function as_array(node) {
|
||||
return node instanceof AST_BlockStatement ? node.body : [ node ];
|
||||
}
|
||||
|
||||
function last_index(stats) {
|
||||
for (var index = stats.length; --index >= 0;) {
|
||||
if (!is_declaration(stats[index], true)) break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
function sequencesize(stat, defuns, var_defs, refs) {
|
||||
if (stat == null) return [];
|
||||
if (stat instanceof AST_BlockStatement) {
|
||||
@@ -9753,7 +9767,7 @@ Compressor.prototype.compress = function(node) {
|
||||
case 0:
|
||||
var prev_block = make_node(AST_BlockStatement, prev, prev);
|
||||
var next_block = make_node(AST_BlockStatement, branch, { body: statements });
|
||||
if (prev_block.equivalent_to(next_block)) prev.body = [];
|
||||
if (prev_block.equals(next_block)) prev.body = [];
|
||||
}
|
||||
}
|
||||
if (side_effects.length) {
|
||||
@@ -11457,7 +11471,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (self.left instanceof AST_SymbolRef
|
||||
&& assign instanceof AST_Assign
|
||||
&& assign.operator == "="
|
||||
&& self.left.equivalent_to(assign.left)) {
|
||||
&& self.left.equals(assign.left)) {
|
||||
return make_node(AST_Assign, self, {
|
||||
operator: "=",
|
||||
left: assign.left,
|
||||
@@ -11483,7 +11497,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
||||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
||||
(self.left.is_boolean(compressor) && self.right.is_boolean(compressor)) ||
|
||||
repeatable(compressor, self.left) && self.left.equivalent_to(self.right)) {
|
||||
repeatable(compressor, self.left) && self.left.equals(self.right)) {
|
||||
self.operator = self.operator.slice(0, 2);
|
||||
}
|
||||
// XXX: intentionally falling down to the next case
|
||||
@@ -11530,7 +11544,7 @@ Compressor.prototype.compress = function(node) {
|
||||
&& (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.equivalent_to(self.right.right)) {
|
||||
&& expr.equals(self.right.right)) {
|
||||
lhs.operator = lhs.operator.slice(0, -1);
|
||||
lhs.left = make_node(AST_Null, self);
|
||||
return self.left;
|
||||
@@ -11542,7 +11556,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (compressor.option("booleans")) {
|
||||
var lhs = self.left;
|
||||
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
|
||||
if (lhs.equivalent_to(self.right)) {
|
||||
if (lhs.equals(self.right)) {
|
||||
return maintain_this_binding(compressor, parent, compressor.self(), lhs).optimize(compressor);
|
||||
}
|
||||
mark_duplicate_condition(compressor, lhs);
|
||||
@@ -12494,7 +12508,7 @@ Compressor.prototype.compress = function(node) {
|
||||
exprs.push(self.right);
|
||||
return make_sequence(self, exprs).optimize(compressor);
|
||||
}
|
||||
if (self.left.equivalent_to(self.right) && !self.left.has_side_effects(compressor)) {
|
||||
if (self.left.equals(self.right) && !self.left.has_side_effects(compressor)) {
|
||||
return self.right;
|
||||
}
|
||||
var exp = self.left.expression;
|
||||
@@ -12510,7 +12524,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
} else if (self.left instanceof AST_SymbolRef && can_drop_symbol(self.left, compressor)) {
|
||||
var parent;
|
||||
if (self.operator == "=" && self.left.equivalent_to(self.right)
|
||||
if (self.operator == "=" && self.left.equals(self.right)
|
||||
&& !((parent = compressor.parent()) instanceof AST_UnaryPrefix && parent.operator == "delete")) {
|
||||
return self.right;
|
||||
}
|
||||
@@ -12697,13 +12711,13 @@ Compressor.prototype.compress = function(node) {
|
||||
var alternative = self.alternative;
|
||||
if (repeatable(compressor, condition)) {
|
||||
// x ? x : y ---> x || y
|
||||
if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, {
|
||||
if (condition.equals(consequent)) return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: condition,
|
||||
right: alternative,
|
||||
}).optimize(compressor);
|
||||
// x ? y : x ---> x && y
|
||||
if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, {
|
||||
if (condition.equals(alternative)) return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: condition,
|
||||
right: consequent,
|
||||
@@ -12720,7 +12734,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if ((is_eq || consequent === seq_tail)
|
||||
&& alt_tail instanceof AST_Assign
|
||||
&& seq_tail.operator == alt_tail.operator
|
||||
&& seq_tail.left.equivalent_to(alt_tail.left)
|
||||
&& seq_tail.left.equals(alt_tail.left)
|
||||
&& (is_eq && seq_tail.left instanceof AST_SymbolRef
|
||||
|| !condition.has_side_effects(compressor)
|
||||
&& can_shift_lhs_of_tail(consequent)
|
||||
@@ -12737,7 +12751,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
}
|
||||
// x ? y : y ---> x, y
|
||||
if (consequent.equivalent_to(alternative)) return make_sequence(self, [
|
||||
if (consequent.equals(alternative)) return make_sequence(self, [
|
||||
condition,
|
||||
consequent
|
||||
]).optimize(compressor);
|
||||
@@ -12751,7 +12765,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (consequent instanceof AST_Call
|
||||
&& alternative.TYPE == consequent.TYPE
|
||||
&& (arg_index = arg_diff(consequent, alternative)) >= 0
|
||||
&& consequent.expression.equivalent_to(alternative.expression)
|
||||
&& consequent.expression.equals(alternative.expression)
|
||||
&& !condition.has_side_effects(compressor)
|
||||
&& !consequent.expression.has_side_effects(compressor)) {
|
||||
var node = consequent.clone();
|
||||
@@ -12771,7 +12785,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// x ? (y ? a : b) : b ---> x && y ? a : b
|
||||
if (consequent instanceof AST_Conditional
|
||||
&& consequent.alternative.equivalent_to(alternative)) {
|
||||
&& consequent.alternative.equals(alternative)) {
|
||||
return make_node(AST_Conditional, self, {
|
||||
condition: make_node(AST_Binary, self, {
|
||||
left: condition,
|
||||
@@ -12784,7 +12798,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// x ? (y ? a : b) : a ---> !x || y ? a : b
|
||||
if (consequent instanceof AST_Conditional
|
||||
&& consequent.consequent.equivalent_to(alternative)) {
|
||||
&& consequent.consequent.equals(alternative)) {
|
||||
return make_node(AST_Conditional, self, {
|
||||
condition: make_node(AST_Binary, self, {
|
||||
left: negated,
|
||||
@@ -12797,7 +12811,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// x ? a : (y ? a : b) ---> x || y ? a : b
|
||||
if (alternative instanceof AST_Conditional
|
||||
&& consequent.equivalent_to(alternative.consequent)) {
|
||||
&& consequent.equals(alternative.consequent)) {
|
||||
return make_node(AST_Conditional, self, {
|
||||
condition: make_node(AST_Binary, self, {
|
||||
left: condition,
|
||||
@@ -12810,7 +12824,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// x ? b : (y ? a : b) ---> !x && y ? a : b
|
||||
if (alternative instanceof AST_Conditional
|
||||
&& consequent.equivalent_to(alternative.alternative)) {
|
||||
&& consequent.equals(alternative.alternative)) {
|
||||
return make_node(AST_Conditional, self, {
|
||||
condition: make_node(AST_Binary, self, {
|
||||
left: negated,
|
||||
@@ -12823,7 +12837,7 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
// x ? (a, c) : (b, c) ---> x ? a : b, c
|
||||
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
|
||||
&& consequent.tail_node().equivalent_to(alternative.tail_node())) {
|
||||
&& consequent.tail_node().equals(alternative.tail_node())) {
|
||||
return make_sequence(self, [
|
||||
make_node(AST_Conditional, self, {
|
||||
condition: condition,
|
||||
@@ -12836,7 +12850,7 @@ Compressor.prototype.compress = function(node) {
|
||||
// x ? y && a : a ---> (!x || y) && a
|
||||
if (consequent instanceof AST_Binary
|
||||
&& consequent.operator == "&&"
|
||||
&& consequent.right.equivalent_to(alternative)) {
|
||||
&& consequent.right.equals(alternative)) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: make_node(AST_Binary, self, {
|
||||
@@ -12850,7 +12864,7 @@ Compressor.prototype.compress = function(node) {
|
||||
// x ? y || a : a ---> x && y || a
|
||||
if (consequent instanceof AST_Binary
|
||||
&& consequent.operator == "||"
|
||||
&& consequent.right.equivalent_to(alternative)) {
|
||||
&& consequent.right.equals(alternative)) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: make_node(AST_Binary, self, {
|
||||
@@ -12864,7 +12878,7 @@ Compressor.prototype.compress = function(node) {
|
||||
// x ? a : y && a ---> (x || y) && a
|
||||
if (alternative instanceof AST_Binary
|
||||
&& alternative.operator == "&&"
|
||||
&& alternative.right.equivalent_to(consequent)) {
|
||||
&& alternative.right.equals(consequent)) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: make_node(AST_Binary, self, {
|
||||
@@ -12878,7 +12892,7 @@ Compressor.prototype.compress = function(node) {
|
||||
// x ? a : y || a ---> !x && y || a
|
||||
if (alternative instanceof AST_Binary
|
||||
&& alternative.operator == "||"
|
||||
&& alternative.right.equivalent_to(consequent)) {
|
||||
&& alternative.right.equals(consequent)) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: make_node(AST_Binary, self, {
|
||||
@@ -12974,10 +12988,10 @@ Compressor.prototype.compress = function(node) {
|
||||
var len = a.length;
|
||||
if (len != b.length) return -2;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (!a[i].equivalent_to(b[i])) {
|
||||
if (!a[i].equals(b[i])) {
|
||||
if (a[i] instanceof AST_Spread !== b[i] instanceof AST_Spread) return -3;
|
||||
for (var j = i + 1; j < len; j++) {
|
||||
if (!a[j].equivalent_to(b[j])) return -2;
|
||||
if (!a[j].equals(b[j])) return -2;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -12998,7 +13012,7 @@ Compressor.prototype.compress = function(node) {
|
||||
if (!(consequent instanceof AST_PropAccess)) return;
|
||||
var p = consequent.property;
|
||||
var q = alternative.property;
|
||||
return (p instanceof AST_Node ? p.equivalent_to(q) : p == q)
|
||||
return (p instanceof AST_Node ? p.equals(q) : p == q)
|
||||
&& !(consequent.expression instanceof AST_Super || alternative.expression instanceof AST_Super);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user