d.assignments++;
var fixed = d.fixed;
if (!fixed) return;
- exp.fixed = d.fixed = function() {
+ d.fixed = function() {
var value = fixed instanceof AST_Node ? fixed : fixed();
return value && make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
})
});
};
+ exp.fixed = node instanceof AST_UnaryPrefix ? d.fixed : function() {
+ var value = fixed instanceof AST_Node ? fixed : fixed();
+ return value && make_node(AST_UnaryPrefix, node, {
+ operator: "+",
+ expression: value
+ });
+ };
if (!safe) return;
d.references.push(exp);
mark(tw, d, true);
&& unaryPrefix[this.operator];
}
});
+ function modified(sym) {
+ if (!(sym instanceof AST_SymbolRef)) return;
+ sym.definition().references.forEach(function(node) {
+ delete node._eval;
+ });
+ }
def(AST_Statement, function() {
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
});
if (this.operator != "=") return this;
var node = this.right;
var value = node._eval(compressor, ignore_side_effects, cached, depth);
+ modified(this.left);
return value === node ? this : value;
});
def(AST_Sequence, function(compressor, ignore_side_effects, cached, depth) {
if (!non_converting_unary[op]) depth++;
var v = e._eval(compressor, ignore_side_effects, cached, depth);
if (v === e) {
- if (ignore_side_effects && op == "void") return void 0;
+ if (ignore_side_effects && op == "void") return;
return this;
}
switch (op) {
// so cannot evaluate reliably
if (v instanceof RegExp) return this;
return typeof v;
- case "void": return void v;
+ case "void": return;
case "~": return ~v;
case "-": return -v;
case "+": return +v;
case "--":
if (!(e instanceof AST_SymbolRef)) return this;
var refs = e.definition().references;
- if (refs[refs.length - 1] !== e) return this;
- return HOP(e, "_eval") ? +(op[0] + 1) + +v : v;
+ if (!ignore_side_effects && refs[refs.length - 1] !== e) return this;
+ if (HOP(e, "_eval")) v = +(op[0] + 1) + +v;
+ modified(e);
+ return v;
}
return this;
});
+ def(AST_UnaryPostfix, function(compressor, ignore_side_effects, cached, depth) {
+ var e = this.expression;
+ if (!(e instanceof AST_SymbolRef)) return this;
+ var refs = e.definition().references;
+ if (!ignore_side_effects && refs[refs.length - 1] !== e) return this;
+ var v = e._eval(compressor, ignore_side_effects, cached, depth + 1);
+ modified(e);
+ return v === e ? this : +v;
+ });
var non_converting_binary = makePredicate("&& || === !==");
def(AST_Binary, function(compressor, ignore_side_effects, cached, depth) {
if (!non_converting_binary[this.operator]) depth++;
}
if (node instanceof AST_Scope && node !== fn) return true;
}));
- if (!found) return void 0;
+ if (!found) return;
}
return this;
}
var args = eval_args(this.args);
- if (!args) return this;
- if (!stat.value) return undefined;
- if (!all(fn.argnames, function(sym, i) {
+ if (!args && !ignore_side_effects) return this;
+ if (!stat.value) return;
+ if (args && !all(fn.argnames, function(sym, i) {
var value = args[i];
var def = sym.definition();
if (def.orig[def.orig.length - 1] !== sym) return false;
cached.push(node);
});
return true;
- })) return this;
+ }) && !ignore_side_effects) return this;
fn.evaluating = true;
var val = stat.value._eval(compressor, ignore_side_effects, cached, depth);
delete fn.evaluating;