|| 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) {
function reversible() {
return self.left.is_constant()
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)) ||
- 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);
}
// XXX: intentionally falling down to the next case
}
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) {
switch (ref) {
case "-":
});
OPT(AST_Conditional, function(self, compressor) {
- if (!compressor.option("conditionals")) return self;
- // This looks like lift_sequences(), should probably be under "sequences"
- if (self.condition instanceof AST_Sequence) {
+ if (compressor.option("sequences") && self.condition instanceof AST_Sequence) {
var expressions = self.condition.expressions.slice();
self.condition = expressions.pop();
expressions.push(self);
return make_sequence(self, expressions);
}
+ if (!compressor.option("conditionals")) return self;
var condition = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
if (!condition) {
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.start);
}
var consequent = self.consequent;
var alternative = self.alternative;
- // x ? x : y => x || y
- if (condition instanceof AST_SymbolRef
- && consequent instanceof AST_SymbolRef
- && condition.definition() === consequent.definition()) {
- return make_node(AST_Binary, self, {
+ if (repeatable(compressor, condition)) {
+ // x ? x : y => x || y
+ if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, {
operator: "||",
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;
// |
expect_stdout: true
}
-condition_symbol_matches_consequent: {
+condition_matches_consequent: {
options = {
conditionals: true,
}
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: {
options = {
booleans: true,