enhance conditionals (#5593)
This commit is contained in:
183
lib/compress.js
183
lib/compress.js
@@ -1749,7 +1749,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function needs_unbinding(compressor, val) {
|
function needs_unbinding(val) {
|
||||||
return val instanceof AST_PropAccess
|
return val instanceof AST_PropAccess
|
||||||
|| is_undeclared_ref(val) && val.name == "eval";
|
|| is_undeclared_ref(val) && val.name == "eval";
|
||||||
}
|
}
|
||||||
@@ -1757,12 +1757,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
// we shouldn't compress (1,func)(something) to
|
// we shouldn't compress (1,func)(something) to
|
||||||
// func(something) because that changes the meaning of
|
// func(something) because that changes the meaning of
|
||||||
// the func (becomes lexical instead of global).
|
// the func (becomes lexical instead of global).
|
||||||
function maintain_this_binding(compressor, parent, orig, val) {
|
function maintain_this_binding(parent, orig, val) {
|
||||||
var wrap = false;
|
var wrap = false;
|
||||||
if (parent.TYPE == "Call") {
|
if (parent.TYPE == "Call") {
|
||||||
wrap = parent.expression === orig && needs_unbinding(compressor, val);
|
wrap = parent.expression === orig && needs_unbinding(val);
|
||||||
} else if (parent instanceof AST_Template) {
|
} else if (parent instanceof AST_Template) {
|
||||||
wrap = parent.tag === orig && needs_unbinding(compressor, val);
|
wrap = parent.tag === orig && needs_unbinding(val);
|
||||||
} else if (parent instanceof AST_UnaryPrefix) {
|
} else if (parent instanceof AST_UnaryPrefix) {
|
||||||
wrap = parent.operator == "delete"
|
wrap = parent.operator == "delete"
|
||||||
|| parent.operator == "typeof" && is_undeclared_ref(val);
|
|| parent.operator == "typeof" && is_undeclared_ref(val);
|
||||||
@@ -2154,7 +2154,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var def = candidate.name.definition();
|
var def = candidate.name.definition();
|
||||||
if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
|
if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
|
||||||
def.replaced++;
|
def.replaced++;
|
||||||
return maintain_this_binding(compressor, parent, node, rvalue);
|
return maintain_this_binding(parent, node, rvalue);
|
||||||
}
|
}
|
||||||
return make_node(AST_Assign, candidate, {
|
return make_node(AST_Assign, candidate, {
|
||||||
operator: "=",
|
operator: "=",
|
||||||
@@ -3340,7 +3340,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
function patch_sequence(node, tt) {
|
function patch_sequence(node, tt) {
|
||||||
if (node instanceof AST_Sequence) switch (node.expressions.length) {
|
if (node instanceof AST_Sequence) switch (node.expressions.length) {
|
||||||
case 0: return null;
|
case 0: return null;
|
||||||
case 1: return maintain_this_binding(compressor, tt.parent(), node, node.expressions[0]);
|
case 1: return maintain_this_binding(tt.parent(), node, node.expressions[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7110,7 +7110,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
case 0:
|
case 0:
|
||||||
return List.skip;
|
return List.skip;
|
||||||
case 1:
|
case 1:
|
||||||
return maintain_this_binding(compressor, parent, node, props[0].transform(tt));
|
return maintain_this_binding(parent, node, props[0].transform(tt));
|
||||||
default:
|
default:
|
||||||
return make_sequence(node, props.map(function(prop) {
|
return make_sequence(node, props.map(function(prop) {
|
||||||
return prop.transform(tt);
|
return prop.transform(tt);
|
||||||
@@ -7599,7 +7599,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Sequence) {
|
if (node instanceof AST_Sequence) {
|
||||||
if (node.expressions.length > 1) return;
|
if (node.expressions.length > 1) return;
|
||||||
return maintain_this_binding(compressor, tt.parent(), node, node.expressions[0]);
|
return maintain_this_binding(tt.parent(), node, node.expressions[0]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tt.push(compressor.parent());
|
tt.push(compressor.parent());
|
||||||
@@ -10316,7 +10316,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
seq.expressions.push(call);
|
seq.expressions.push(call);
|
||||||
return seq.optimize(compressor);
|
return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
} else if (!needs_unbinding(compressor, exp.tail_node())) {
|
} else if (!needs_unbinding(exp.tail_node())) {
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
@@ -10549,7 +10549,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
&& is_undeclared_ref(exp.expression)
|
&& is_undeclared_ref(exp.expression)
|
||||||
&& exp.expression.name == "Object") {
|
&& exp.expression.name == "Object") {
|
||||||
var call = self.clone();
|
var call = self.clone();
|
||||||
call.expression = maintain_this_binding(compressor, self, exp, exp.args[0]);
|
call.expression = maintain_this_binding(self, exp, exp.args[0]);
|
||||||
return call.optimize(compressor);
|
return call.optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10673,7 +10673,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (!arg) return make_node(AST_Undefined, self);
|
if (!arg) return make_node(AST_Undefined, self);
|
||||||
args[index] = null;
|
args[index] = null;
|
||||||
var parent = this.parent();
|
var parent = this.parent();
|
||||||
return parent ? maintain_this_binding(compressor, parent, node, arg) : arg;
|
return parent ? maintain_this_binding(parent, node, arg) : arg;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
var save_inlined = fn.inlined;
|
var save_inlined = fn.inlined;
|
||||||
@@ -10690,7 +10690,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
exprs.push(retValue);
|
exprs.push(retValue);
|
||||||
var node = make_sequence(self, exprs).optimize(compressor);
|
var node = make_sequence(self, exprs).optimize(compressor);
|
||||||
fn.inlined = save_inlined;
|
fn.inlined = save_inlined;
|
||||||
node = maintain_this_binding(compressor, parent, current, node);
|
node = maintain_this_binding(parent, current, node);
|
||||||
if (replacing || best_of_expression(node, self) === node) {
|
if (replacing || best_of_expression(node, self) === node) {
|
||||||
refs.forEach(function(ref) {
|
refs.forEach(function(ref) {
|
||||||
ref.scope = exp === fn ? fn.parent_scope : exp.scope;
|
ref.scope = exp === fn ? fn.parent_scope : exp.scope;
|
||||||
@@ -10714,7 +10714,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
fn._squeezed = true;
|
fn._squeezed = true;
|
||||||
if (exp !== fn) fn.parent_scope = exp.scope;
|
if (exp !== fn) fn.parent_scope = exp.scope;
|
||||||
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
||||||
return maintain_this_binding(compressor, parent, current, node);
|
return maintain_this_binding(parent, current, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects")
|
if (compressor.option("side_effects")
|
||||||
@@ -11244,7 +11244,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
merge_assignments();
|
merge_assignments();
|
||||||
trim_right_for_undefined();
|
trim_right_for_undefined();
|
||||||
if (end == 0) {
|
if (end == 0) {
|
||||||
self = maintain_this_binding(compressor, compressor.parent(), compressor.self(), expressions[0]);
|
self = maintain_this_binding(compressor.parent(), compressor.self(), expressions[0]);
|
||||||
if (!(self instanceof AST_Sequence)) self = self.optimize(compressor);
|
if (!(self instanceof AST_Sequence)) self = self.optimize(compressor);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -11674,7 +11674,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var lhs = self.left;
|
var lhs = self.left;
|
||||||
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
|
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
|
||||||
if (lhs.equals(self.right)) {
|
if (lhs.equals(self.right)) {
|
||||||
return maintain_this_binding(compressor, parent, compressor.self(), lhs).optimize(compressor);
|
return maintain_this_binding(parent, compressor.self(), lhs).optimize(compressor);
|
||||||
}
|
}
|
||||||
mark_duplicate_condition(compressor, lhs);
|
mark_duplicate_condition(compressor, lhs);
|
||||||
}
|
}
|
||||||
@@ -11770,7 +11770,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var ll = fuzzy_eval(compressor, self.left);
|
var ll = fuzzy_eval(compressor, self.left);
|
||||||
if (!ll) {
|
if (!ll) {
|
||||||
AST_Node.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
AST_Node.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
||||||
return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor);
|
return maintain_this_binding(parent, compressor.self(), self.left).optimize(compressor);
|
||||||
} else if (!(ll instanceof AST_Node)) {
|
} else if (!(ll instanceof AST_Node)) {
|
||||||
AST_Node.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
AST_Node.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
||||||
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
|
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
|
||||||
@@ -11816,7 +11816,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
line: self.start.line,
|
line: self.start.line,
|
||||||
col: self.start.col,
|
col: self.start.col,
|
||||||
});
|
});
|
||||||
return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor);
|
return maintain_this_binding(parent, compressor.self(), self.left).optimize(compressor);
|
||||||
}
|
}
|
||||||
var rr;
|
var rr;
|
||||||
if (!nullish && (rr = self.right.evaluate(compressor, true)) && !(rr instanceof AST_Node)) {
|
if (!nullish && (rr = self.right.evaluate(compressor, true)) && !(rr instanceof AST_Node)) {
|
||||||
@@ -12781,16 +12781,17 @@ Compressor.prototype.compress = function(node) {
|
|||||||
operator: self.operator.slice(0, -1),
|
operator: self.operator.slice(0, -1),
|
||||||
left: self.left,
|
left: self.left,
|
||||||
right: self.right,
|
right: self.right,
|
||||||
}) : maintain_this_binding(compressor, compressor.parent(), self, self.right)).optimize(compressor);
|
}) : maintain_this_binding(compressor.parent(), self, self.right)).optimize(compressor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Conditional, function(self, compressor) {
|
OPT(AST_Conditional, function(self, compressor) {
|
||||||
if (compressor.option("sequences") && self.condition instanceof AST_Sequence) {
|
if (compressor.option("sequences") && self.condition instanceof AST_Sequence) {
|
||||||
var expressions = self.condition.expressions.slice();
|
var expressions = self.condition.expressions.slice();
|
||||||
self.condition = expressions.pop();
|
var node = self.clone();
|
||||||
expressions.push(self);
|
node.condition = expressions.pop();
|
||||||
return make_sequence(self, expressions);
|
expressions.push(node);
|
||||||
|
return make_sequence(self, expressions).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (!compressor.option("conditionals")) return self;
|
if (!compressor.option("conditionals")) return self;
|
||||||
var condition = self.condition;
|
var condition = self.condition;
|
||||||
@@ -12854,16 +12855,27 @@ Compressor.prototype.compress = function(node) {
|
|||||||
right: make_node(AST_Conditional, self, {
|
right: make_node(AST_Conditional, self, {
|
||||||
condition: condition,
|
condition: condition,
|
||||||
consequent: pop_lhs(consequent),
|
consequent: pop_lhs(consequent),
|
||||||
alternative: pop_lhs(alternative)
|
alternative: pop_lhs(alternative),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var alt_tail = alternative.tail_node();
|
||||||
// x ? y : y ---> x, y
|
// x ? y : y ---> x, y
|
||||||
if (consequent.equals(alternative)) return make_sequence(self, [
|
// x ? (a, c) : (b, c) ---> x ? a : b, c
|
||||||
condition,
|
if (seq_tail.equals(alt_tail)) {
|
||||||
consequent
|
return make_sequence(self, consequent.equals(alternative) ? [
|
||||||
]).optimize(compressor);
|
condition,
|
||||||
|
consequent,
|
||||||
|
] : [
|
||||||
|
make_node(AST_Conditional, self, {
|
||||||
|
condition: condition,
|
||||||
|
consequent: pop_seq(consequent),
|
||||||
|
alternative: pop_seq(alternative),
|
||||||
|
}),
|
||||||
|
seq_tail,
|
||||||
|
]).optimize(compressor);
|
||||||
|
}
|
||||||
// x ? y.p : z.p ---> (x ? y : z).p
|
// x ? y.p : z.p ---> (x ? y : z).p
|
||||||
// x ? y(a) : z(a) ---> (x ? y : z)(a)
|
// x ? y(a) : z(a) ---> (x ? y : z)(a)
|
||||||
// x ? y.f(a) : z.f(a) ---> (x ? y : z).f(a)
|
// x ? y.f(a) : z.f(a) ---> (x ? y : z).f(a)
|
||||||
@@ -12893,123 +12905,111 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
// x ? (y ? a : b) : b ---> x && y ? a : b
|
// x ? (y ? a : b) : b ---> x && y ? a : b
|
||||||
if (consequent instanceof AST_Conditional
|
if (seq_tail instanceof AST_Conditional
|
||||||
&& consequent.alternative.equals(alternative)) {
|
&& seq_tail.alternative.equals(alternative)) {
|
||||||
return make_node(AST_Conditional, self, {
|
return make_node(AST_Conditional, self, {
|
||||||
condition: make_node(AST_Binary, self, {
|
condition: make_node(AST_Binary, self, {
|
||||||
left: condition,
|
left: condition,
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
right: consequent.condition
|
right: fuse(consequent, seq_tail, "condition"),
|
||||||
}),
|
}),
|
||||||
consequent: consequent.consequent,
|
consequent: seq_tail.consequent,
|
||||||
alternative: alternative
|
alternative: alternative,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x ? (y ? a : b) : a ---> !x || y ? a : b
|
// x ? (y ? a : b) : a ---> !x || y ? a : b
|
||||||
if (consequent instanceof AST_Conditional
|
if (seq_tail instanceof AST_Conditional
|
||||||
&& consequent.consequent.equals(alternative)) {
|
&& seq_tail.consequent.equals(alternative)) {
|
||||||
return make_node(AST_Conditional, self, {
|
return make_node(AST_Conditional, self, {
|
||||||
condition: make_node(AST_Binary, self, {
|
condition: make_node(AST_Binary, self, {
|
||||||
left: negated,
|
left: negated,
|
||||||
operator: "||",
|
operator: "||",
|
||||||
right: consequent.condition
|
right: fuse(consequent, seq_tail, "condition"),
|
||||||
}),
|
}),
|
||||||
consequent: alternative,
|
consequent: alternative,
|
||||||
alternative: consequent.alternative
|
alternative: seq_tail.alternative,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x ? a : (y ? a : b) ---> x || y ? a : b
|
// x ? a : (y ? a : b) ---> x || y ? a : b
|
||||||
if (alternative instanceof AST_Conditional
|
if (alt_tail instanceof AST_Conditional
|
||||||
&& consequent.equals(alternative.consequent)) {
|
&& consequent.equals(alt_tail.consequent)) {
|
||||||
return make_node(AST_Conditional, self, {
|
return make_node(AST_Conditional, self, {
|
||||||
condition: make_node(AST_Binary, self, {
|
condition: make_node(AST_Binary, self, {
|
||||||
left: condition,
|
left: condition,
|
||||||
operator: "||",
|
operator: "||",
|
||||||
right: alternative.condition
|
right: fuse(alternative, alt_tail, "condition"),
|
||||||
}),
|
}),
|
||||||
consequent: consequent,
|
consequent: consequent,
|
||||||
alternative: alternative.alternative
|
alternative: alt_tail.alternative,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x ? b : (y ? a : b) ---> !x && y ? a : b
|
// x ? b : (y ? a : b) ---> !x && y ? a : b
|
||||||
if (alternative instanceof AST_Conditional
|
if (alt_tail instanceof AST_Conditional
|
||||||
&& consequent.equals(alternative.alternative)) {
|
&& consequent.equals(alt_tail.alternative)) {
|
||||||
return make_node(AST_Conditional, self, {
|
return make_node(AST_Conditional, self, {
|
||||||
condition: make_node(AST_Binary, self, {
|
condition: make_node(AST_Binary, self, {
|
||||||
left: negated,
|
left: negated,
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
right: alternative.condition
|
right: fuse(alternative, alt_tail, "condition"),
|
||||||
}),
|
}),
|
||||||
consequent: alternative.consequent,
|
consequent: alt_tail.consequent,
|
||||||
alternative: consequent
|
alternative: consequent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x ? (a, c) : (b, c) ---> x ? a : b, c
|
|
||||||
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
|
|
||||||
&& consequent.tail_node().equals(alternative.tail_node())) {
|
|
||||||
return make_sequence(self, [
|
|
||||||
make_node(AST_Conditional, self, {
|
|
||||||
condition: condition,
|
|
||||||
consequent: pop_seq(consequent),
|
|
||||||
alternative: pop_seq(alternative)
|
|
||||||
}),
|
|
||||||
consequent.tail_node()
|
|
||||||
]).optimize(compressor);
|
|
||||||
}
|
|
||||||
// x ? y && a : a ---> (!x || y) && a
|
// x ? y && a : a ---> (!x || y) && a
|
||||||
if (consequent instanceof AST_Binary
|
if (seq_tail instanceof AST_Binary
|
||||||
&& consequent.operator == "&&"
|
&& seq_tail.operator == "&&"
|
||||||
&& consequent.right.equals(alternative)) {
|
&& seq_tail.right.equals(alternative)) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: make_node(AST_Binary, self, {
|
left: make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: negated,
|
left: negated,
|
||||||
right: consequent.left
|
right: fuse(consequent, seq_tail, "left"),
|
||||||
}),
|
}),
|
||||||
right: alternative
|
right: alternative,
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
// x ? y || a : a ---> x && y || a
|
// x ? y || a : a ---> x && y || a
|
||||||
if (consequent instanceof AST_Binary
|
if (seq_tail instanceof AST_Binary
|
||||||
&& consequent.operator == "||"
|
&& seq_tail.operator == "||"
|
||||||
&& consequent.right.equals(alternative)) {
|
&& seq_tail.right.equals(alternative)) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: make_node(AST_Binary, self, {
|
left: make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: condition,
|
left: condition,
|
||||||
right: consequent.left
|
right: fuse(consequent, seq_tail, "left"),
|
||||||
}),
|
}),
|
||||||
right: alternative
|
right: alternative,
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
// x ? a : y && a ---> (x || y) && a
|
// x ? a : y && a ---> (x || y) && a
|
||||||
if (alternative instanceof AST_Binary
|
if (alt_tail instanceof AST_Binary
|
||||||
&& alternative.operator == "&&"
|
&& alt_tail.operator == "&&"
|
||||||
&& alternative.right.equals(consequent)) {
|
&& alt_tail.right.equals(consequent)) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: make_node(AST_Binary, self, {
|
left: make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: condition,
|
left: condition,
|
||||||
right: alternative.left
|
right: fuse(alternative, alt_tail, "left"),
|
||||||
}),
|
}),
|
||||||
right: consequent
|
right: consequent,
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
// x ? a : y || a ---> !x && y || a
|
// x ? a : y || a ---> !x && y || a
|
||||||
if (alternative instanceof AST_Binary
|
if (alt_tail instanceof AST_Binary
|
||||||
&& alternative.operator == "||"
|
&& alt_tail.operator == "||"
|
||||||
&& alternative.right.equals(consequent)) {
|
&& alt_tail.right.equals(consequent)) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: make_node(AST_Binary, self, {
|
left: make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: negated,
|
left: negated,
|
||||||
right: alternative.left
|
right: fuse(alternative, alt_tail, "left"),
|
||||||
}),
|
}),
|
||||||
right: consequent
|
right: consequent,
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
||||||
@@ -13022,7 +13022,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: booleanize(condition),
|
left: booleanize(condition),
|
||||||
right: alternative
|
right: alternative,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (is_false(consequent)) {
|
if (is_false(consequent)) {
|
||||||
@@ -13034,7 +13034,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: booleanize(condition.negate(compressor)),
|
left: booleanize(condition.negate(compressor)),
|
||||||
right: alternative
|
right: alternative,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (is_true(alternative)) {
|
if (is_true(alternative)) {
|
||||||
@@ -13042,7 +13042,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "||",
|
operator: "||",
|
||||||
left: booleanize(condition.negate(compressor)),
|
left: booleanize(condition.negate(compressor)),
|
||||||
right: consequent
|
right: consequent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (is_false(alternative)) {
|
if (is_false(alternative)) {
|
||||||
@@ -13050,7 +13050,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: booleanize(condition),
|
left: booleanize(condition),
|
||||||
right: consequent
|
right: consequent,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (compressor.option("typeofs")) mark_locally_defined(condition, consequent, alternative);
|
if (compressor.option("typeofs")) mark_locally_defined(condition, consequent, alternative);
|
||||||
@@ -13108,6 +13108,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fuse(node, tail, prop) {
|
||||||
|
if (node === tail) return tail[prop];
|
||||||
|
var exprs = node.expressions.slice(0, -1);
|
||||||
|
exprs.push(tail[prop]);
|
||||||
|
return make_sequence(node, exprs);
|
||||||
|
}
|
||||||
|
|
||||||
function is_tail_equivalent(consequent, alternative) {
|
function is_tail_equivalent(consequent, alternative) {
|
||||||
if (consequent.TYPE != alternative.TYPE) return;
|
if (consequent.TYPE != alternative.TYPE) return;
|
||||||
if (consequent.optional != alternative.optional) return;
|
if (consequent.optional != alternative.optional) return;
|
||||||
@@ -13126,13 +13133,21 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function combine_tail(consequent, alternative, top) {
|
function combine_tail(consequent, alternative, top) {
|
||||||
if (!is_tail_equivalent(consequent, alternative)) return !top && make_node(AST_Conditional, self, {
|
var seq_tail = consequent.tail_node();
|
||||||
|
var alt_tail = alternative.tail_node();
|
||||||
|
if (!is_tail_equivalent(seq_tail, alt_tail)) return !top && make_node(AST_Conditional, self, {
|
||||||
condition: condition,
|
condition: condition,
|
||||||
consequent: consequent,
|
consequent: consequent,
|
||||||
alternative: alternative,
|
alternative: alternative,
|
||||||
});
|
});
|
||||||
var node = consequent.clone();
|
var node = seq_tail.clone();
|
||||||
node.expression = combine_tail(consequent.expression, alternative.expression);
|
var seq_expr = fuse(consequent, seq_tail, "expression");
|
||||||
|
var alt_expr = fuse(alternative, alt_tail, "expression");
|
||||||
|
var combined = combine_tail(seq_expr, alt_expr);
|
||||||
|
if (seq_tail.expression instanceof AST_Sequence) {
|
||||||
|
combined = maintain_this_binding(seq_tail, seq_tail.expression, combined);
|
||||||
|
}
|
||||||
|
node.expression = combined;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1433,6 +1433,398 @@ condition_matches_alternative: {
|
|||||||
expect_stdout: "null 0 false 5"
|
expect_stdout: "null 0 false 5"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition_sequence_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y) {
|
||||||
|
return (console.log(x), x) ? x : y;
|
||||||
|
}
|
||||||
|
console.log(f("foo", "bar"));
|
||||||
|
console.log(f(null, "baz"));
|
||||||
|
console.log(f(42));
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y) {
|
||||||
|
return console.log(x), x || y;
|
||||||
|
}
|
||||||
|
console.log(f("foo", "bar")),
|
||||||
|
console.log(f(null, "baz")),
|
||||||
|
console.log(f(42)),
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"foo",
|
||||||
|
"null",
|
||||||
|
"baz",
|
||||||
|
"42",
|
||||||
|
"42",
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
condition_sequence_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y) {
|
||||||
|
return (console.log(y), y) ? x : y;
|
||||||
|
}
|
||||||
|
console.log(f("foo", "bar"));
|
||||||
|
console.log(f(null, "baz"));
|
||||||
|
console.log(f(42));
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y) {
|
||||||
|
return console.log(y), y && x;
|
||||||
|
}
|
||||||
|
console.log(f("foo", "bar")),
|
||||||
|
console.log(f(null, "baz")),
|
||||||
|
console.log(f(42)),
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"bar",
|
||||||
|
"foo",
|
||||||
|
"baz",
|
||||||
|
"null",
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
combine_tail_sequence: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var n = {
|
||||||
|
f: function() {
|
||||||
|
console.log("foo");
|
||||||
|
return this.p;
|
||||||
|
},
|
||||||
|
p: "FAIL 1",
|
||||||
|
};
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
console.log("foz");
|
||||||
|
return this.p;
|
||||||
|
},
|
||||||
|
p: "FAIL 2",
|
||||||
|
};
|
||||||
|
var p = "PASS";
|
||||||
|
function g(a) {
|
||||||
|
return a
|
||||||
|
? (console.log("baa"), (console.log("bar"), (console.log("baz"), n).f)())
|
||||||
|
: (console.log("moo"), (console.log("mor"), (console.log("moz"), o).f)());
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
console.log(g(42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var n = {
|
||||||
|
f: function() {
|
||||||
|
console.log("foo");
|
||||||
|
return this.p;
|
||||||
|
},
|
||||||
|
p: "FAIL 1",
|
||||||
|
};
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
console.log("foz");
|
||||||
|
return this.p;
|
||||||
|
},
|
||||||
|
p: "FAIL 2",
|
||||||
|
};
|
||||||
|
var p = "PASS";
|
||||||
|
function g(a) {
|
||||||
|
return (0, (a
|
||||||
|
? (console.log("baa"), console.log("bar"), console.log("baz"), n)
|
||||||
|
: (console.log("moo"), console.log("mor"), console.log("moz"), o)).f)();
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
console.log(g(42));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"moo",
|
||||||
|
"mor",
|
||||||
|
"moz",
|
||||||
|
"foz",
|
||||||
|
"PASS",
|
||||||
|
"baa",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
|
"foo",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
consequent_sequence_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return x ? (console.log("seq"), y && a) : a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return (!x || (console.log("seq"), y)) && a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"seq",
|
||||||
|
"false",
|
||||||
|
"seq",
|
||||||
|
"4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
consequent_sequence_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return x ? (console.log("seq"), y || a) : a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return x && (console.log("seq"), y) || a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"seq",
|
||||||
|
"3",
|
||||||
|
"seq",
|
||||||
|
"true",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
consequent_sequence_3: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return x ? (console.log("seq"), y ? a : b) : b;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return x && (console.log("seq"), y) ? a : b;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"-1",
|
||||||
|
"-2",
|
||||||
|
"seq",
|
||||||
|
"-3",
|
||||||
|
"seq",
|
||||||
|
"4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
consequent_sequence_4: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return x ? (console.log("seq"), y ? a : b) : a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return !x || (console.log("seq"), y) ? a : b;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"seq",
|
||||||
|
"-3",
|
||||||
|
"seq",
|
||||||
|
"4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
alternative_sequence_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return x ? a : (console.log("seq"), y && a);
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return (x || (console.log("seq"), y)) && a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"seq",
|
||||||
|
"false",
|
||||||
|
"seq",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
alternative_sequence_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return x ? a : (console.log("seq"), y || a);
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a) {
|
||||||
|
return !x && (console.log("seq"), y) || a;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1));
|
||||||
|
console.log(f(false, true, 2));
|
||||||
|
console.log(f(true, false, 3));
|
||||||
|
console.log(f(true, true, 4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"seq",
|
||||||
|
"1",
|
||||||
|
"seq",
|
||||||
|
"true",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
alternative_sequence_3: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return x ? a : (console.log("seq"), y ? a : b);
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return x || (console.log("seq"), y) ? a : b;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"seq",
|
||||||
|
"-1",
|
||||||
|
"seq",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
alternative_sequence_4: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return x ? b : (console.log("seq"), y ? a : b);
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x, y, a, b) {
|
||||||
|
return !x && (console.log("seq"), y) ? a : b;
|
||||||
|
}
|
||||||
|
console.log(f(false, false, 1, -1));
|
||||||
|
console.log(f(false, true, 2, -2));
|
||||||
|
console.log(f(true, false, 3, -3));
|
||||||
|
console.log(f(true, true, 4, -4));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"seq",
|
||||||
|
"-1",
|
||||||
|
"seq",
|
||||||
|
"2",
|
||||||
|
"-3",
|
||||||
|
"-4",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
delete_conditional_1: {
|
delete_conditional_1: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user