1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
if(!dojo._hasResource["dojox.lang.functional.lambda"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.lang.functional.lambda"] = true;
dojo.provide("dojox.lang.functional.lambda");
// 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
(function(){
var df = dojox.lang.functional;
// 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) || [];
var t = {};
dojo.forEach(vars, function(v){
if(!(v in t)){
args.push(v);
t[v] = 1;
}
});
}
}
return {args: args, body: "return (" + 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; };
};
dojo.mixin(df, {
// lambda
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(",") + "){" + 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); }
s = lambda(s);
return new Function(s.args, s.body); // Function
}
});
})();
}
|