enhance conditionals (#4181)
This commit is contained in:
@@ -7463,6 +7463,15 @@ merge(Compressor.prototype, {
|
|||||||
|| node instanceof AST_Object;
|
|| node instanceof AST_Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor) {
|
OPT(AST_Binary, function(self, compressor) {
|
||||||
function reversible() {
|
function reversible() {
|
||||||
return self.left.is_constant()
|
return self.left.is_constant()
|
||||||
@@ -7531,7 +7540,7 @@ merge(Compressor.prototype, {
|
|||||||
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
||||||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
||||||
(self.left.is_boolean(compressor) && self.right.is_boolean(compressor)) ||
|
(self.left.is_boolean(compressor) && self.right.is_boolean(compressor)) ||
|
||||||
can_self_compare(self.left) && self.left.equivalent_to(self.right)) {
|
repeatable(compressor, self.left) && self.left.equivalent_to(self.right)) {
|
||||||
self.operator = self.operator.slice(0, 2);
|
self.operator = self.operator.slice(0, 2);
|
||||||
}
|
}
|
||||||
// XXX: intentionally falling down to the next case
|
// XXX: intentionally falling down to the next case
|
||||||
@@ -8036,13 +8045,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return try_evaluate(compressor, self);
|
return try_evaluate(compressor, self);
|
||||||
|
|
||||||
function can_self_compare(node) {
|
|
||||||
if (node instanceof AST_Dot) return can_self_compare(node.expression);
|
|
||||||
if (node instanceof AST_Sub) return can_self_compare(node.expression) && can_self_compare(node.property);
|
|
||||||
if (node instanceof AST_Symbol) return true;
|
|
||||||
return !node.has_side_effects(compressor);
|
|
||||||
}
|
|
||||||
|
|
||||||
function align(ref, op) {
|
function align(ref, op) {
|
||||||
switch (ref) {
|
switch (ref) {
|
||||||
case "-":
|
case "-":
|
||||||
@@ -8504,14 +8506,13 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Conditional, function(self, compressor) {
|
OPT(AST_Conditional, function(self, compressor) {
|
||||||
if (!compressor.option("conditionals")) return self;
|
if (compressor.option("sequences") && self.condition instanceof AST_Sequence) {
|
||||||
// This looks like lift_sequences(), should probably be under "sequences"
|
|
||||||
if (self.condition instanceof AST_Sequence) {
|
|
||||||
var expressions = self.condition.expressions.slice();
|
var expressions = self.condition.expressions.slice();
|
||||||
self.condition = expressions.pop();
|
self.condition = expressions.pop();
|
||||||
expressions.push(self);
|
expressions.push(self);
|
||||||
return make_sequence(self, expressions);
|
return make_sequence(self, expressions);
|
||||||
}
|
}
|
||||||
|
if (!compressor.option("conditionals")) return self;
|
||||||
var condition = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
var condition = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.start);
|
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.start);
|
||||||
@@ -8532,15 +8533,19 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var consequent = self.consequent;
|
var consequent = self.consequent;
|
||||||
var alternative = self.alternative;
|
var alternative = self.alternative;
|
||||||
|
if (repeatable(compressor, condition)) {
|
||||||
// x ? x : y => x || y
|
// x ? x : y => x || y
|
||||||
if (condition instanceof AST_SymbolRef
|
if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, {
|
||||||
&& consequent instanceof AST_SymbolRef
|
|
||||||
&& condition.definition() === consequent.definition()) {
|
|
||||||
return make_node(AST_Binary, self, {
|
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: condition,
|
left: condition,
|
||||||
right: alternative
|
right: alternative,
|
||||||
});
|
}).optimize(compressor);
|
||||||
|
// x ? y : x => x && y
|
||||||
|
if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, {
|
||||||
|
operator: "&&",
|
||||||
|
left: condition,
|
||||||
|
right: consequent,
|
||||||
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
// if (foo) exp = something; else exp = something_else;
|
// if (foo) exp = something; else exp = something_else;
|
||||||
// |
|
// |
|
||||||
|
|||||||
@@ -1159,7 +1159,7 @@ issue_1645_2: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
condition_symbol_matches_consequent: {
|
condition_matches_consequent: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
}
|
}
|
||||||
@@ -1188,6 +1188,35 @@ condition_symbol_matches_consequent: {
|
|||||||
expect_stdout: "3 7 true 4"
|
expect_stdout: "3 7 true 4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition_matches_alternative: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(x, y) {
|
||||||
|
return x.p ? y[0] : x.p;
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
return g ? h : g;
|
||||||
|
}
|
||||||
|
var g = 4;
|
||||||
|
var h = 5;
|
||||||
|
console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(x, y) {
|
||||||
|
return x.p && y[0];
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
return g && h;
|
||||||
|
}
|
||||||
|
var g = 4;
|
||||||
|
var h = 5;
|
||||||
|
console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar());
|
||||||
|
}
|
||||||
|
expect_stdout: "null 0 false 5"
|
||||||
|
}
|
||||||
|
|
||||||
delete_conditional_1: {
|
delete_conditional_1: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user