函数重载库Overload
2009-07-02 14:24 Cat Chen 阅读(754) 评论(0) 编辑 收藏 举报(function() {
Overload = {};
var copySignature = function(signature) {
var copy = [];
for (var i = 0; i < signature.length; i++) {
copy.push(signature[i]);
}
if (signature.arguments) {
copy.arguments = true;
}
return copy;
};
var inheritanceComparator = function(type1, type2) {
if (type1 == type2) {
return 0;
} else if (type2 == Overload.Any) {
return 1;
} else if (type1 == Overload.Any) {
return -1;
} else if (type1.prototype instanceof type2) {
return 1;
} else if (type2.prototype instanceof type1) {
return -1;
} else {
return 0;
}
};
var overloadComparator = function(overload1, overload2) {
var signature1Better = false;
var signature2Better = false;
var signature1 = overload1.signature;
var signature2 = overload2.signature;
if (!signature1.more && signature2.more) {
signature1Better = true;
signature1 = copySignature(signature1);
signature1.length = signature2.length;
} else if (signature1.more && !signature2.more) {
signature2Better = true;
signature2 = copySignature(signature2);
signature2.length = signature1.length;
} else if(signature1.more && signature2.more) {
if (signature1.length > signature2.length) {
signature2 = copySignature(signature2);
while (signature2.length < signature1.length) {
signature2[signature2.length] = Overload.Any;
}
} else if (signature1.length < signature2.length) {
signature1 = copySignature(signature1);
while (signature1.length < signature2.length) {
signature1[signature1.length] = Overload.Any;
}
}
}
for (var i = 0; i < signature1.length; i++) {
var comparison = inheritanceComparator(signature1[i], signature2[i]);
if (comparison > 0) {
signature1Better = true;
} else if (comparison < 0) {
signature2Better = true;
}
}
if (signature1Better && !signature2Better) {
return 1;
} else if (!signature1Better && signature2Better) {
return -1;
} else {
return 0;
}
};
var matchSignature = function(argumentsArray, signature) {
if (argumentsArray.length < signature.length) {
return false;
} else if (argumentsArray.length > signature.length && !signature.more) {
return false;
}
for (var i = 0; i < signature.length; i++) {
if (!(signature[i] == Overload.Any
|| argumentsArray[i] instanceof signature[i]
|| argumentsArray[i].constructor == signature[i])) {
return false;
}
}
return true;
};
Overload.create = function(overloadsArray) {
var overloads = [];
var select = function(argumentsArray) {
var matches = [];
for (var i = 0; i < overloads.length; i++) {
if (matchSignature(argumentsArray, overloads[i].signature)) {
matches.push(overloads[i]);
}
}
switch (matches.length) {
case 0:
return null;
case 1:
return matches[0]["function"];
default:
matches = matches.sort(overloadComparator);
if (overloadComparator(matches[matches.length - 1], matches[matches.length - 2]) > 0) {
return matches[matches.length - 1]["function"];
} else {
return null;
}
}
};
var overloaded = function() {
var overload = select(arguments);
if (overload) {
return overload.apply(this, arguments);
} else {
throw "cannot select a proper overload";
}
};
overloaded.select = select;
overloaded.add = function(signature, overload) {
if (signature instanceof Array) {
signature = copySignature(signature);
} else if (signature.constructor == String) {
if (signature.replace(/(^\s+|\s+$)/ig, "") == "") {
signature = [];
} else {
signature = signature.split(",");
for (var i = 0; i < signature.length; i++) {
var typeExpression = signature[i].replace(/(^\s+|\s+$)/ig, "");
var type = null;
if (typeExpression == "*") {
type = Overload.Any;
} else if (typeExpression == "...") {
type = Overload.More;
} else {
try {
type = eval("(" + typeExpression + ")");
} catch (error) {
throw "type expression cannot be evaluated: " + typeExpression;
}
}
signature[i] = type;
}
}
} else {
throw "signature is neither a string nor an array";
}
for (var i = 0; i < signature.length; i++) {
if (!(signature[i] instanceof Function)) {
throw "argument type should be a function";
}
if (i < signature.length - 1 && signature[i] == Overload.More) {
throw "arguments type cannot be used in any argument except the last one";
}
}
if (signature[signature.length - 1] == Overload.More) {
signature.length = signature.length - 1;
signature.more = true;
}
overloads.push({
"signature": signature,
"function": overload
});
return this;
};
return overloaded;
};
Overload.add = function(signature, overload) {
return Overload.create().add(signature, overload);
};
Overload.Any = function any() {
throw "this type is only an identifier and should not be instantiated"
};
Overload.More = function more() {
throw "this type is only an identifier and should not be instantiated"
};
})();
Overload = {};
var copySignature = function(signature) {
var copy = [];
for (var i = 0; i < signature.length; i++) {
copy.push(signature[i]);
}
if (signature.arguments) {
copy.arguments = true;
}
return copy;
};
var inheritanceComparator = function(type1, type2) {
if (type1 == type2) {
return 0;
} else if (type2 == Overload.Any) {
return 1;
} else if (type1 == Overload.Any) {
return -1;
} else if (type1.prototype instanceof type2) {
return 1;
} else if (type2.prototype instanceof type1) {
return -1;
} else {
return 0;
}
};
var overloadComparator = function(overload1, overload2) {
var signature1Better = false;
var signature2Better = false;
var signature1 = overload1.signature;
var signature2 = overload2.signature;
if (!signature1.more && signature2.more) {
signature1Better = true;
signature1 = copySignature(signature1);
signature1.length = signature2.length;
} else if (signature1.more && !signature2.more) {
signature2Better = true;
signature2 = copySignature(signature2);
signature2.length = signature1.length;
} else if(signature1.more && signature2.more) {
if (signature1.length > signature2.length) {
signature2 = copySignature(signature2);
while (signature2.length < signature1.length) {
signature2[signature2.length] = Overload.Any;
}
} else if (signature1.length < signature2.length) {
signature1 = copySignature(signature1);
while (signature1.length < signature2.length) {
signature1[signature1.length] = Overload.Any;
}
}
}
for (var i = 0; i < signature1.length; i++) {
var comparison = inheritanceComparator(signature1[i], signature2[i]);
if (comparison > 0) {
signature1Better = true;
} else if (comparison < 0) {
signature2Better = true;
}
}
if (signature1Better && !signature2Better) {
return 1;
} else if (!signature1Better && signature2Better) {
return -1;
} else {
return 0;
}
};
var matchSignature = function(argumentsArray, signature) {
if (argumentsArray.length < signature.length) {
return false;
} else if (argumentsArray.length > signature.length && !signature.more) {
return false;
}
for (var i = 0; i < signature.length; i++) {
if (!(signature[i] == Overload.Any
|| argumentsArray[i] instanceof signature[i]
|| argumentsArray[i].constructor == signature[i])) {
return false;
}
}
return true;
};
Overload.create = function(overloadsArray) {
var overloads = [];
var select = function(argumentsArray) {
var matches = [];
for (var i = 0; i < overloads.length; i++) {
if (matchSignature(argumentsArray, overloads[i].signature)) {
matches.push(overloads[i]);
}
}
switch (matches.length) {
case 0:
return null;
case 1:
return matches[0]["function"];
default:
matches = matches.sort(overloadComparator);
if (overloadComparator(matches[matches.length - 1], matches[matches.length - 2]) > 0) {
return matches[matches.length - 1]["function"];
} else {
return null;
}
}
};
var overloaded = function() {
var overload = select(arguments);
if (overload) {
return overload.apply(this, arguments);
} else {
throw "cannot select a proper overload";
}
};
overloaded.select = select;
overloaded.add = function(signature, overload) {
if (signature instanceof Array) {
signature = copySignature(signature);
} else if (signature.constructor == String) {
if (signature.replace(/(^\s+|\s+$)/ig, "") == "") {
signature = [];
} else {
signature = signature.split(",");
for (var i = 0; i < signature.length; i++) {
var typeExpression = signature[i].replace(/(^\s+|\s+$)/ig, "");
var type = null;
if (typeExpression == "*") {
type = Overload.Any;
} else if (typeExpression == "...") {
type = Overload.More;
} else {
try {
type = eval("(" + typeExpression + ")");
} catch (error) {
throw "type expression cannot be evaluated: " + typeExpression;
}
}
signature[i] = type;
}
}
} else {
throw "signature is neither a string nor an array";
}
for (var i = 0; i < signature.length; i++) {
if (!(signature[i] instanceof Function)) {
throw "argument type should be a function";
}
if (i < signature.length - 1 && signature[i] == Overload.More) {
throw "arguments type cannot be used in any argument except the last one";
}
}
if (signature[signature.length - 1] == Overload.More) {
signature.length = signature.length - 1;
signature.more = true;
}
overloads.push({
"signature": signature,
"function": overload
});
return this;
};
return overloaded;
};
Overload.add = function(signature, overload) {
return Overload.create().add(signature, overload);
};
Overload.Any = function any() {
throw "this type is only an identifier and should not be instantiated"
};
Overload.More = function more() {
throw "this type is only an identifier and should not be instantiated"
};
})();