refactor throw usage within compress (#2193)
Eliminate exceptional constructs from normal control flow.
This commit is contained in:
207
lib/compress.js
207
lib/compress.js
@@ -1198,21 +1198,21 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0, len = statements.length; i < len; i++) {
|
for (var i = 0, len = statements.length; i < len; i++) {
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (stat instanceof AST_For) {
|
if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
|
||||||
try {
|
var abort = false;
|
||||||
prev.body.walk(new TreeWalker(function(node){
|
prev.body.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Binary && node.operator == "in")
|
if (abort) return true;
|
||||||
throw cons_seq;
|
if (node instanceof AST_Binary && node.operator == "in") {
|
||||||
}));
|
abort = true;
|
||||||
if (stat.init && !(stat.init instanceof AST_Definitions)) {
|
return true;
|
||||||
stat.init = cons_seq(stat.init);
|
|
||||||
}
|
}
|
||||||
else if (!stat.init) {
|
}));
|
||||||
|
if (!abort) {
|
||||||
|
if (stat.init) stat.init = cons_seq(stat.init);
|
||||||
|
else {
|
||||||
stat.init = prev.body.drop_side_effect_free(compressor);
|
stat.init = prev.body.drop_side_effect_free(compressor);
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== cons_seq) throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (stat instanceof AST_If) {
|
else if (stat instanceof AST_If) {
|
||||||
@@ -1532,13 +1532,8 @@ merge(Compressor.prototype, {
|
|||||||
// descendant of AST_Node.
|
// descendant of AST_Node.
|
||||||
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
||||||
if (!compressor.option("evaluate")) return this;
|
if (!compressor.option("evaluate")) return this;
|
||||||
try {
|
var val = this._eval(compressor);
|
||||||
var val = this._eval(compressor);
|
return !val || val instanceof RegExp || typeof val != "object" ? val : this;
|
||||||
return !val || val instanceof RegExp || typeof val != "object" ? val : this;
|
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== def) throw ex;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
var unaryPrefix = makePredicate("! ~ - + void");
|
var unaryPrefix = makePredicate("! ~ - + void");
|
||||||
AST_Node.DEFMETHOD("is_constant", function(){
|
AST_Node.DEFMETHOD("is_constant", function(){
|
||||||
@@ -1584,27 +1579,28 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Statement, function(){
|
def(AST_Statement, function(){
|
||||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||||
});
|
});
|
||||||
def(AST_Lambda, function(){
|
def(AST_Lambda, return_this);
|
||||||
throw def;
|
|
||||||
});
|
|
||||||
function ev(node, compressor) {
|
function ev(node, compressor) {
|
||||||
if (!compressor) throw new Error("Compressor must be passed");
|
if (!compressor) throw new Error("Compressor must be passed");
|
||||||
|
|
||||||
return node._eval(compressor);
|
return node._eval(compressor);
|
||||||
};
|
};
|
||||||
def(AST_Node, function(){
|
def(AST_Node, return_this);
|
||||||
throw def; // not constant
|
|
||||||
});
|
|
||||||
def(AST_Constant, function(){
|
def(AST_Constant, function(){
|
||||||
return this.getValue();
|
return this.getValue();
|
||||||
});
|
});
|
||||||
def(AST_Array, function(compressor){
|
def(AST_Array, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
return this.elements.map(function(element) {
|
var elements = [];
|
||||||
return ev(element, compressor);
|
for (var i = 0, len = this.elements.length; i < len; i++) {
|
||||||
});
|
var element = this.elements[i];
|
||||||
|
var value = ev(element, compressor);
|
||||||
|
if (element === value) return this;
|
||||||
|
elements.push(value);
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor){
|
def(AST_Object, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
@@ -1616,105 +1612,121 @@ merge(Compressor.prototype, {
|
|||||||
key = key.name;
|
key = key.name;
|
||||||
} else if (key instanceof AST_Node) {
|
} else if (key instanceof AST_Node) {
|
||||||
key = ev(key, compressor);
|
key = ev(key, compressor);
|
||||||
|
if (key === prop.key) return this;
|
||||||
}
|
}
|
||||||
if (typeof Object.prototype[key] === 'function') {
|
if (typeof Object.prototype[key] === 'function') {
|
||||||
throw def;
|
return this;
|
||||||
}
|
}
|
||||||
val[key] = ev(prop.value, compressor);
|
val[key] = ev(prop.value, compressor);
|
||||||
|
if (val[key] === prop.value) return this;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_UnaryPrefix, function(compressor){
|
def(AST_UnaryPrefix, function(compressor){
|
||||||
var e = this.expression;
|
// Function would be evaluated to an array and so typeof would
|
||||||
|
// incorrectly return 'object'. Hence making is a special case.
|
||||||
|
if (this.operator == "typeof" && this.expression instanceof AST_Function) {
|
||||||
|
return typeof function(){};
|
||||||
|
}
|
||||||
|
var e = ev(this.expression, compressor);
|
||||||
|
if (e === this.expression) return this;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "!": return !ev(e, compressor);
|
case "!": return !e;
|
||||||
case "typeof":
|
case "typeof":
|
||||||
// Function would be evaluated to an array and so typeof would
|
|
||||||
// incorrectly return 'object'. Hence making is a special case.
|
|
||||||
if (e instanceof AST_Function) return typeof function(){};
|
|
||||||
|
|
||||||
e = ev(e, compressor);
|
|
||||||
|
|
||||||
// typeof <RegExp> returns "object" or "function" on different platforms
|
// typeof <RegExp> returns "object" or "function" on different platforms
|
||||||
// so cannot evaluate reliably
|
// so cannot evaluate reliably
|
||||||
if (e instanceof RegExp) throw def;
|
if (e instanceof RegExp) return this;
|
||||||
|
|
||||||
return typeof e;
|
return typeof e;
|
||||||
case "void": return void ev(e, compressor);
|
case "void": return void e;
|
||||||
case "~": return ~ev(e, compressor);
|
case "~": return ~e;
|
||||||
case "-": return -ev(e, compressor);
|
case "-": return -e;
|
||||||
case "+": return +ev(e, compressor);
|
case "+": return +e;
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(c){
|
def(AST_Binary, function(compressor){
|
||||||
var left = this.left, right = this.right, result;
|
var left = ev(this.left, compressor);
|
||||||
|
if (left === this.left) return this;
|
||||||
|
var right = ev(this.right, compressor);
|
||||||
|
if (right === this.right) return this;
|
||||||
|
var result;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&" : result = ev(left, c) && ev(right, c); break;
|
case "&&" : result = left && right; break;
|
||||||
case "||" : result = ev(left, c) || ev(right, c); break;
|
case "||" : result = left || right; break;
|
||||||
case "|" : result = ev(left, c) | ev(right, c); break;
|
case "|" : result = left | right; break;
|
||||||
case "&" : result = ev(left, c) & ev(right, c); break;
|
case "&" : result = left & right; break;
|
||||||
case "^" : result = ev(left, c) ^ ev(right, c); break;
|
case "^" : result = left ^ right; break;
|
||||||
case "+" : result = ev(left, c) + ev(right, c); break;
|
case "+" : result = left + right; break;
|
||||||
case "*" : result = ev(left, c) * ev(right, c); break;
|
case "*" : result = left * right; break;
|
||||||
case "/" : result = ev(left, c) / ev(right, c); break;
|
case "/" : result = left / right; break;
|
||||||
case "%" : result = ev(left, c) % ev(right, c); break;
|
case "%" : result = left % right; break;
|
||||||
case "-" : result = ev(left, c) - ev(right, c); break;
|
case "-" : result = left - right; break;
|
||||||
case "<<" : result = ev(left, c) << ev(right, c); break;
|
case "<<" : result = left << right; break;
|
||||||
case ">>" : result = ev(left, c) >> ev(right, c); break;
|
case ">>" : result = left >> right; break;
|
||||||
case ">>>" : result = ev(left, c) >>> ev(right, c); break;
|
case ">>>" : result = left >>> right; break;
|
||||||
case "==" : result = ev(left, c) == ev(right, c); break;
|
case "==" : result = left == right; break;
|
||||||
case "===" : result = ev(left, c) === ev(right, c); break;
|
case "===" : result = left === right; break;
|
||||||
case "!=" : result = ev(left, c) != ev(right, c); break;
|
case "!=" : result = left != right; break;
|
||||||
case "!==" : result = ev(left, c) !== ev(right, c); break;
|
case "!==" : result = left !== right; break;
|
||||||
case "<" : result = ev(left, c) < ev(right, c); break;
|
case "<" : result = left < right; break;
|
||||||
case "<=" : result = ev(left, c) <= ev(right, c); break;
|
case "<=" : result = left <= right; break;
|
||||||
case ">" : result = ev(left, c) > ev(right, c); break;
|
case ">" : result = left > right; break;
|
||||||
case ">=" : result = ev(left, c) >= ev(right, c); break;
|
case ">=" : result = left >= right; break;
|
||||||
default:
|
default:
|
||||||
throw def;
|
return this;
|
||||||
}
|
}
|
||||||
if (isNaN(result) && c.find_parent(AST_With)) {
|
if (isNaN(result) && compressor.find_parent(AST_With)) {
|
||||||
// leave original expression as is
|
// leave original expression as is
|
||||||
throw def;
|
return this;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
return ev(this.condition, compressor)
|
var condition = ev(this.condition, compressor);
|
||||||
? ev(this.consequent, compressor)
|
if (condition === this.condition) return this;
|
||||||
: ev(this.alternative, compressor);
|
var node = condition ? this.consequent : this.alternative;
|
||||||
|
var value = ev(node, compressor);
|
||||||
|
return value === node ? this : value;
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor){
|
def(AST_SymbolRef, function(compressor){
|
||||||
if (!compressor.option("reduce_vars") || this._evaluating) throw def;
|
if (!compressor.option("reduce_vars")) return this;
|
||||||
this._evaluating = true;
|
this._eval = return_this;
|
||||||
try {
|
var fixed = this.fixed_value();
|
||||||
var fixed = this.fixed_value();
|
if (!fixed) {
|
||||||
if (!fixed) throw def;
|
delete this._eval;
|
||||||
var value = ev(fixed, compressor);
|
return this;
|
||||||
if (!HOP(fixed, "_eval")) fixed._eval = function() {
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
if (value && typeof value == "object" && this.definition().escaped) throw def;
|
|
||||||
return value;
|
|
||||||
} finally {
|
|
||||||
this._evaluating = false;
|
|
||||||
}
|
}
|
||||||
|
var value = ev(fixed, compressor);
|
||||||
|
if (value === fixed) {
|
||||||
|
delete this._eval;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (!HOP(fixed, "_eval")) fixed._eval = function() {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
if (value && typeof value == "object" && this.definition().escaped) {
|
||||||
|
delete this._eval;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this._eval = fixed._eval;
|
||||||
|
return value;
|
||||||
});
|
});
|
||||||
def(AST_PropAccess, function(compressor){
|
def(AST_PropAccess, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var key = this.property;
|
var key = this.property;
|
||||||
if (key instanceof AST_Node) {
|
if (key instanceof AST_Node) {
|
||||||
key = ev(key, compressor);
|
key = ev(key, compressor);
|
||||||
|
if (key === this.property) return this;
|
||||||
}
|
}
|
||||||
var val = ev(this.expression, compressor);
|
var val = ev(this.expression, compressor);
|
||||||
|
if (val === this.expression) return this;
|
||||||
if (val && HOP(val, key)) {
|
if (val && HOP(val, key)) {
|
||||||
return val[key];
|
return val[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
var object_fns = [
|
var object_fns = [
|
||||||
'constructor',
|
'constructor',
|
||||||
@@ -1760,19 +1772,24 @@ merge(Compressor.prototype, {
|
|||||||
var key = exp.property;
|
var key = exp.property;
|
||||||
if (key instanceof AST_Node) {
|
if (key instanceof AST_Node) {
|
||||||
key = ev(key, compressor);
|
key = ev(key, compressor);
|
||||||
|
if (key === exp.property) return this;
|
||||||
}
|
}
|
||||||
var val = ev(exp.expression, compressor);
|
var val = ev(exp.expression, compressor);
|
||||||
|
if (val === exp.expression) return this;
|
||||||
if ((val && native_fns[val.constructor.name] || return_false)(key)) {
|
if ((val && native_fns[val.constructor.name] || return_false)(key)) {
|
||||||
return val[key].apply(val, this.args.map(function(arg) {
|
var args = [];
|
||||||
return ev(arg, compressor);
|
for (var i = 0, len = this.args.length; i < len; i++) {
|
||||||
}));
|
var arg = this.args[i];
|
||||||
|
var value = ev(arg, compressor);
|
||||||
|
if (arg === value) return this;
|
||||||
|
args.push(value);
|
||||||
|
}
|
||||||
|
return val[key].apply(val, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
|
||||||
def(AST_New, function(compressor){
|
|
||||||
throw def;
|
|
||||||
});
|
});
|
||||||
|
def(AST_New, return_this);
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("_eval", func);
|
node.DEFMETHOD("_eval", func);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user