Skip to content

Commit

Permalink
enhance evaluate (#3714)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed Feb 12, 2020
1 parent f4c7788 commit dd22eda
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 48 deletions.
93 changes: 52 additions & 41 deletions lib/compress.js
Expand Up @@ -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;
});
Expand Down Expand Up @@ -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() {};
Expand All @@ -3115,20 +3128,20 @@ 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);
}
return elements;
}
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++) {
Expand All @@ -3137,22 +3150,22 @@ 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;
}
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.
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -3235,22 +3248,22 @@ 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;
if (member(fixed, cached)) {
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() {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}
Expand Down Expand Up @@ -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, [
Expand Down Expand Up @@ -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, {
Expand Down Expand Up @@ -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")) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 = [];
Expand All @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 2 additions & 7 deletions test/compress/reduce_vars.js
Expand Up @@ -2071,13 +2071,8 @@ issue_1670_6: {
}
expect: {
(function(a) {
switch (1) {
case a = 1:
console.log(a);
break;
default:
console.log(2);
}
a = 1;
console.log(a);
})(1);
}
expect_stdout: "1"
Expand Down

0 comments on commit dd22eda

Please sign in to comment.