aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/compress.js93
1 files changed, 52 insertions, 41 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 0fcd199e..55e40ef2 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -3073,10 +3073,10 @@ merge(Compressor.prototype, {
// is returned.
// They can be distinguished as constant value is never a
// descendant of AST_Node.
- AST_Node.DEFMETHOD("evaluate", function(compressor) {
+ AST_Node.DEFMETHOD("evaluate", function(compressor, ignore_side_effects) {
if (!compressor.option("evaluate")) return this;
var cached = [];
- var val = this._eval(compressor, cached, 1);
+ var val = this._eval(compressor, ignore_side_effects, cached, 1);
cached.forEach(function(node) {
delete node._eval;
});
@@ -3104,6 +3104,19 @@ merge(Compressor.prototype, {
def(AST_Constant, function() {
return this.value;
});
+ def(AST_Assign, function(compressor, ignore_side_effects, cached, depth) {
+ if (!ignore_side_effects) return this;
+ if (this.operator != "=") return this;
+ var node = this.right;
+ var value = node._eval(compressor, ignore_side_effects, cached, depth);
+ return value === node ? this : value;
+ });
+ def(AST_Sequence, function(compressor, ignore_side_effects, cached, depth) {
+ if (!ignore_side_effects) return this;
+ var node = this.tail_node();
+ var value = node._eval(compressor, ignore_side_effects, cached, depth);
+ return value === node ? this : value;
+ });
def(AST_Function, function(compressor) {
if (compressor.option("unsafe")) {
var fn = function() {};
@@ -3115,12 +3128,12 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Array, function(compressor, cached, depth) {
+ def(AST_Array, function(compressor, ignore_side_effects, cached, depth) {
if (compressor.option("unsafe")) {
var elements = [];
for (var i = 0; i < this.elements.length; i++) {
var element = this.elements[i];
- var value = element._eval(compressor, cached, depth);
+ var value = element._eval(compressor, ignore_side_effects, cached, depth);
if (element === value) return this;
elements.push(value);
}
@@ -3128,7 +3141,7 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Object, function(compressor, cached, depth) {
+ def(AST_Object, function(compressor, ignore_side_effects, cached, depth) {
if (compressor.option("unsafe")) {
var val = {};
for (var i = 0; i < this.properties.length; i++) {
@@ -3137,14 +3150,14 @@ merge(Compressor.prototype, {
if (key instanceof AST_Symbol) {
key = key.name;
} else if (key instanceof AST_Node) {
- key = key._eval(compressor, cached, depth);
+ key = key._eval(compressor, ignore_side_effects, cached, depth);
if (key === prop.key) return this;
}
if (typeof Object.prototype[key] === 'function') {
return this;
}
if (prop.value instanceof AST_Function) continue;
- val[key] = prop.value._eval(compressor, cached, depth);
+ val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
if (val[key] === prop.value) return this;
}
return val;
@@ -3152,7 +3165,7 @@ merge(Compressor.prototype, {
return this;
});
var non_converting_unary = makePredicate("! typeof void");
- def(AST_UnaryPrefix, function(compressor, cached, depth) {
+ def(AST_UnaryPrefix, function(compressor, ignore_side_effects, cached, depth) {
var e = this.expression;
// Function would be evaluated to an array and so typeof would
// incorrectly return 'object'. Hence making is a special case.
@@ -3164,7 +3177,7 @@ merge(Compressor.prototype, {
return typeof function(){};
}
if (!non_converting_unary[this.operator]) depth++;
- var v = e._eval(compressor, cached, depth);
+ var v = e._eval(compressor, ignore_side_effects, cached, depth);
if (v === this.expression) return this;
switch (this.operator) {
case "!": return !v;
@@ -3187,12 +3200,12 @@ merge(Compressor.prototype, {
return this;
});
var non_converting_binary = makePredicate("&& || === !==");
- def(AST_Binary, function(compressor, cached, depth) {
+ def(AST_Binary, function(compressor, ignore_side_effects, cached, depth) {
if (!non_converting_binary[this.operator]) depth++;
- var left = this.left._eval(compressor, cached, depth);
+ var left = this.left._eval(compressor, ignore_side_effects, cached, depth);
if (left === this.left) return this;
if (this.operator == (left ? "||" : "&&")) return left;
- var right = this.right._eval(compressor, cached, depth);
+ var right = this.right._eval(compressor, ignore_side_effects, cached, depth);
if (right === this.right) return this;
var result;
switch (this.operator) {
@@ -3235,14 +3248,14 @@ merge(Compressor.prototype, {
return (match[1] || ".").length - 1 - (match[2] || "").slice(1);
}
});
- def(AST_Conditional, function(compressor, cached, depth) {
- var condition = this.condition._eval(compressor, cached, depth);
+ def(AST_Conditional, function(compressor, ignore_side_effects, cached, depth) {
+ var condition = this.condition._eval(compressor, ignore_side_effects, cached, depth);
if (condition === this.condition) return this;
var node = condition ? this.consequent : this.alternative;
- var value = node._eval(compressor, cached, depth);
+ var value = node._eval(compressor, ignore_side_effects, cached, depth);
return value === node ? this : value;
});
- def(AST_SymbolRef, function(compressor, cached, depth) {
+ def(AST_SymbolRef, function(compressor, ignore_side_effects, cached, depth) {
var fixed = this.fixed_value();
if (!fixed) return this;
var value;
@@ -3250,7 +3263,7 @@ merge(Compressor.prototype, {
value = fixed._eval();
} else {
this._eval = return_this;
- value = fixed._eval(compressor, cached, depth);
+ value = fixed._eval(compressor, ignore_side_effects, cached, depth);
delete this._eval;
if (value === fixed) return this;
fixed._eval = function() {
@@ -3307,11 +3320,11 @@ merge(Compressor.prototype, {
],
});
var regexp_props = makePredicate("global ignoreCase multiline source");
- def(AST_PropAccess, function(compressor, cached, depth) {
+ def(AST_PropAccess, function(compressor, ignore_side_effects, cached, depth) {
if (compressor.option("unsafe")) {
var key = this.property;
if (key instanceof AST_Node) {
- key = key._eval(compressor, cached, depth);
+ key = key._eval(compressor, ignore_side_effects, cached, depth);
if (key === this.property) return this;
}
var exp = this.expression;
@@ -3321,7 +3334,7 @@ merge(Compressor.prototype, {
if (!static_value || !static_value[key]) return this;
val = global_objs[exp.name];
} else {
- val = exp._eval(compressor, cached, depth + 1);
+ val = exp._eval(compressor, ignore_side_effects, cached, depth + 1);
if (val == null || val === exp) return this;
if (val instanceof RegExp) {
if (!regexp_props[key]) return this;
@@ -3340,7 +3353,7 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Call, function(compressor, cached, depth) {
+ def(AST_Call, function(compressor, ignore_side_effects, cached, depth) {
var exp = this.expression;
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
if (fn instanceof AST_Lambda) {
@@ -3361,14 +3374,14 @@ merge(Compressor.prototype, {
});
});
fn.evaluating = true;
- var val = stat.value._eval(compressor, cached, depth);
+ var val = stat.value._eval(compressor, ignore_side_effects, cached, depth);
delete fn.evaluating;
if (val === stat.value) return this;
return val;
} else if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
var key = exp.property;
if (key instanceof AST_Node) {
- key = key._eval(compressor, cached, depth);
+ key = key._eval(compressor, ignore_side_effects, cached, depth);
if (key === exp.property) return this;
}
var val;
@@ -3378,7 +3391,7 @@ merge(Compressor.prototype, {
if (!static_fn || !static_fn[key]) return this;
val = global_objs[e.name];
} else {
- val = e._eval(compressor, cached, depth + 1);
+ val = e._eval(compressor, ignore_side_effects, cached, depth + 1);
if (val == null || val === e) return this;
var native_fn = native_fns[val.constructor.name];
if (!native_fn || !native_fn[key]) return this;
@@ -3403,7 +3416,7 @@ merge(Compressor.prototype, {
var values = [];
for (var i = 0; i < args.length; i++) {
var arg = args[i];
- var value = arg._eval(compressor, cached, depth);
+ var value = arg._eval(compressor, ignore_side_effects, cached, depth);
if (arg === value) return;
values.push(value);
}
@@ -4478,7 +4491,7 @@ merge(Compressor.prototype, {
node.in_bool = true;
var value = node.value;
if (value) {
- var ev = value.is_truthy() || value.tail_node().evaluate(compressor);
+ var ev = value.is_truthy() || value.evaluate(compressor, true);
if (!ev) {
value = value.drop_side_effect_free(compressor);
node.value = value ? make_sequence(node.value, [
@@ -4878,7 +4891,7 @@ merge(Compressor.prototype, {
OPT(AST_Do, function(self, compressor) {
if (!compressor.option("loops")) return self;
- var cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
+ var cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
if (!(cond instanceof AST_Node)) {
if (cond) return make_node(AST_For, self, {
body: make_node(AST_BlockStatement, self.body, {
@@ -5008,16 +5021,14 @@ merge(Compressor.prototype, {
}
if (self.condition) {
var cond = self.condition.evaluate(compressor);
- if (!(cond instanceof AST_Node)) {
- if (cond) self.condition = null;
- else if (!compressor.option("dead_code")) {
- var orig = self.condition;
- self.condition = make_node_from_constant(cond, self.condition);
- self.condition = best_of_expression(self.condition.transform(compressor), orig);
- }
- }
if (cond instanceof AST_Node) {
- cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
+ cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
+ } else if (cond) {
+ self.condition = null;
+ } else if (!compressor.option("dead_code")) {
+ var orig = self.condition;
+ self.condition = make_node_from_constant(cond, self.condition);
+ self.condition = best_of_expression(self.condition.transform(compressor), orig);
}
if (!cond) {
if (compressor.option("dead_code")) {
@@ -5109,7 +5120,7 @@ merge(Compressor.prototype, {
}
if (compressor.option("dead_code")) {
if (cond instanceof AST_Node) {
- cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
+ cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
}
if (!cond) {
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
@@ -5255,7 +5266,7 @@ merge(Compressor.prototype, {
}
if (!compressor.option("dead_code")) return self;
if (value instanceof AST_Node) {
- value = self.expression.tail_node().evaluate(compressor);
+ value = self.expression.evaluate(compressor, true);
}
var decl = [];
var body = [];
@@ -5277,7 +5288,7 @@ merge(Compressor.prototype, {
eliminate_branch(branch, body[body.length - 1]);
continue;
}
- if (exp instanceof AST_Node) exp = branch.expression.tail_node().evaluate(compressor);
+ if (exp instanceof AST_Node) exp = branch.expression.evaluate(compressor, true);
if (exp === value) {
exact_match = branch;
if (default_branch) {
@@ -6461,7 +6472,7 @@ merge(Compressor.prototype, {
}
// (x || false) && y => x ? y : false
if (self.left.operator == "||") {
- var lr = self.left.right.tail_node().evaluate(compressor);
+ var lr = self.left.right.evaluate(compressor, true);
if (!lr) return make_node(AST_Conditional, self, {
condition: self.left.left,
consequent: self.right,
@@ -6495,7 +6506,7 @@ merge(Compressor.prototype, {
}
// x && true || y => x ? true : y
if (self.left.operator == "&&") {
- var lr = self.left.right.is_truthy() || self.left.right.tail_node().evaluate(compressor);
+ var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true);
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
condition: self.left.left,
consequent: self.left.right,