134 lines
4.3 KiB
JavaScript
134 lines
4.3 KiB
JavaScript
//>>built
|
|
define("dojox/lang/functional/lambda", ["../..", "dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array"], function(dojox, dojo, lang, arr){
|
|
var df = lang.getObject("lang.functional", true, dojox);
|
|
|
|
// This module adds high-level functions and related constructs:
|
|
// - anonymous functions built from the string
|
|
|
|
// Acknoledgements:
|
|
// - lambda() is based on work by Oliver Steele
|
|
// (http://osteele.com/sources/javascript/functional/functional.js)
|
|
// which was published under MIT License
|
|
|
|
// Notes:
|
|
// - lambda() produces functions, which after the compilation step are
|
|
// as fast as regular JS functions (at least theoretically).
|
|
|
|
// Lambda input values:
|
|
// - returns functions unchanged
|
|
// - converts strings to functions
|
|
// - converts arrays to a functional composition
|
|
|
|
var lcache = {};
|
|
|
|
// split() is augmented on IE6 to ensure the uniform behavior
|
|
var split = "ab".split(/a*/).length > 1 ? String.prototype.split :
|
|
function(sep){
|
|
var r = this.split.call(this, sep),
|
|
m = sep.exec(this);
|
|
if(m && m.index == 0){ r.unshift(""); }
|
|
return r;
|
|
};
|
|
|
|
var lambda = function(/*String*/ s){
|
|
var args = [], sects = split.call(s, /\s*->\s*/m);
|
|
if(sects.length > 1){
|
|
while(sects.length){
|
|
s = sects.pop();
|
|
args = sects.pop().split(/\s*,\s*|\s+/m);
|
|
if(sects.length){ sects.push("(function(" + args + "){return (" + s + ")})"); }
|
|
}
|
|
}else if(s.match(/\b_\b/)){
|
|
args = ["_"];
|
|
}else{
|
|
var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m),
|
|
r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m);
|
|
if(l || r){
|
|
if(l){
|
|
args.push("$1");
|
|
s = "$1" + s;
|
|
}
|
|
if(r){
|
|
args.push("$2");
|
|
s = s + "$2";
|
|
}
|
|
}else{
|
|
// the point of the long regex below is to exclude all well-known
|
|
// lower-case words from the list of potential arguments
|
|
var vars = s.
|
|
replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, "").
|
|
match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {};
|
|
arr.forEach(vars, function(v){
|
|
if(!(v in t)){
|
|
args.push(v);
|
|
t[v] = 1;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return {args: args, body: s}; // Object
|
|
};
|
|
|
|
var compose = function(/*Array*/ a){
|
|
return a.length ?
|
|
function(){
|
|
var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments);
|
|
for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); }
|
|
return x;
|
|
}
|
|
:
|
|
// identity
|
|
function(x){ return x; };
|
|
};
|
|
|
|
lang.mixin(df, {
|
|
// lambda
|
|
rawLambda: function(/*String*/ s){
|
|
// summary:
|
|
// builds a function from a snippet, or array (composing),
|
|
// returns an object describing the function; functions are
|
|
// passed through unmodified.
|
|
// description:
|
|
// This method is to normalize a functional representation (a
|
|
// text snippet) to an object that contains an array of
|
|
// arguments, and a body , which is used to calculate the
|
|
// returning value.
|
|
return lambda(s); // Object
|
|
},
|
|
buildLambda: function(/*String*/ s){
|
|
// summary:
|
|
// builds a function from a snippet, returns a string, which
|
|
// represents the function.
|
|
// description:
|
|
// This method returns a textual representation of a function
|
|
// built from the snippet. It is meant to be evaled in the
|
|
// proper context, so local variables can be pulled from the
|
|
// environment.
|
|
s = lambda(s);
|
|
return "function(" + s.args.join(",") + "){return (" + s.body + ");}"; // String
|
|
},
|
|
lambda: function(/*Function|String|Array*/ s){
|
|
// summary:
|
|
// builds a function from a snippet, or array (composing),
|
|
// returns a function object; functions are passed through
|
|
// unmodified.
|
|
// description:
|
|
// This method is used to normalize a functional
|
|
// representation (a text snippet, an array, or a function) to
|
|
// a function object.
|
|
if(typeof s == "function"){ return s; }
|
|
if(s instanceof Array){ return compose(s); }
|
|
if(s in lcache){ return lcache[s]; }
|
|
s = lambda(s);
|
|
return lcache[s] = new Function(s.args, "return (" + s.body + ");"); // Function
|
|
},
|
|
clearLambdaCache: function(){
|
|
// summary:
|
|
// clears internal cache of lambdas
|
|
lcache = {};
|
|
}
|
|
});
|
|
|
|
return df;
|
|
});
|