source: Dev/trunk/src/client/dojox/lang/functional/lambda.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 4.3 KB
Line 
1define(["../..", "dojo/_base/lang", "dojo/_base/array"], function(dojox, lang, arr){
2        var df = lang.getObject("lang.functional", true, dojox);
3
4// This module adds high-level functions and related constructs:
5//      - anonymous functions built from the string
6
7// Acknowledgements:
8//      - lambda() is based on work by Oliver Steele
9//              (http://osteele.com/sources/javascript/functional/functional.js)
10//              which was published under MIT License
11
12// Notes:
13//      - lambda() produces functions, which after the compilation step are
14//              as fast as regular JS functions (at least theoretically).
15
16// Lambda input values:
17//      - returns functions unchanged
18//      - converts strings to functions
19//      - converts arrays to a functional composition
20
21        var lcache = {};
22
23        // split() is augmented on IE6 to ensure the uniform behavior
24        var split = "ab".split(/a*/).length > 1 ? String.prototype.split :
25                        function(sep){
26                                 var r = this.split.call(this, sep),
27                                         m = sep.exec(this);
28                                 if(m && m.index == 0){ r.unshift(""); }
29                                 return r;
30                        };
31                       
32        var lambda = function(/*String*/ s){
33                var args = [], sects = split.call(s, /\s*->\s*/m);
34                if(sects.length > 1){
35                        while(sects.length){
36                                s = sects.pop();
37                                args = sects.pop().split(/\s*,\s*|\s+/m);
38                                if(sects.length){ sects.push("(function(" + args.join(", ") + "){ return (" + s + "); })"); }
39                        }
40                }else if(s.match(/\b_\b/)){
41                        args = ["_"];
42                }else{
43                        var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m),
44                                r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m);
45                        if(l || r){
46                                if(l){
47                                        args.push("$1");
48                                        s = "$1" + s;
49                                }
50                                if(r){
51                                        args.push("$2");
52                                        s = s + "$2";
53                                }
54                        }else{
55                                // the point of the long regex below is to exclude all well-known
56                                // lower-case words from the list of potential arguments
57                                var vars = s.
58                                        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, "").
59                                        match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {};
60                                arr.forEach(vars, function(v){
61                                        if(!t.hasOwnProperty(v)){
62                                                args.push(v);
63                                                t[v] = 1;
64                                        }
65                                });
66                        }
67                }
68                return {args: args, body: s};   // Object
69        };
70
71        var compose = function(/*Array*/ a){
72                return a.length ?
73                                        function(){
74                                                var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments);
75                                                for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); }
76                                                return x;
77                                        }
78                                :
79                                        // identity
80                                        function(x){ return x; };
81        };
82
83        lang.mixin(df, {
84                // lambda
85                rawLambda: function(/*String*/ s){
86                        // summary:
87                        //              builds a function from a snippet, or array (composing),
88                        //              returns an object describing the function; functions are
89                        //              passed through unmodified.
90                        // description:
91                        //              This method is to normalize a functional representation (a
92                        //              text snippet) to an object that contains an array of
93                        //              arguments, and a body , which is used to calculate the
94                        //              returning value.
95                        return lambda(s);       // Object
96                },
97                buildLambda: function(/*String*/ s){
98                        // summary:
99                        //              builds a function from a snippet, returns a string, which
100                        //              represents the function.
101                        // description:
102                        //              This method returns a textual representation of a function
103                        //              built from the snippet. It is meant to be evaled in the
104                        //              proper context, so local variables can be pulled from the
105                        //              environment.
106                        var l = lambda(s);
107                        return "function(" + l.args.join(",") + "){return (" + l.body + ");}";  // String
108                },
109                lambda: function(/*Function|String|Array*/ s){
110                        // summary:
111                        //              builds a function from a snippet, or array (composing),
112                        //              returns a function object; functions are passed through
113                        //              unmodified.
114                        // description:
115                        //              This method is used to normalize a functional
116                        //              representation (a text snippet, an array, or a function) to
117                        //              a function object.
118                        if(typeof s == "function"){ return s; }
119                        if(s instanceof Array){ return compose(s); }
120                        if(lcache.hasOwnProperty(s)){ return lcache[s]; }
121                        var l = lambda(s);
122                        return lcache[s] = new Function(l.args, "return (" + l.body + ");");    // Function
123                },
124                clearLambdaCache: function(){
125                        // summary:
126                        //              clears internal cache of lambdas
127                        lcache = {};
128                }
129        });
130       
131        return df;
132});
Note: See TracBrowser for help on using the repository browser.