source: Dev/branches/rest-dojo-ui/client/dojox/lang/functional/multirec.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 5.1 KB
Line 
1dojo.provide("dojox.lang.functional.multirec");
2
3dojo.require("dojox.lang.functional.lambda");
4dojo.require("dojox.lang.functional.util");
5
6// This module provides recursion combinators:
7//      - a multi-way recursion combinator.
8
9// Acknoledgements:
10//      - recursion combinators are inspired by Manfred von Thun's article
11//              "Recursion Theory and Joy"
12//              (http://www.latrobe.edu.au/philosophy/phimvt/joy/j05cmp.html)
13
14// Notes:
15//      - recursion combinators produce a function, which implements
16//      their respective recusion patterns. String lambdas are inlined, if possible.
17
18(function(){
19        var df = dojox.lang.functional, inline = df.inlineLambda,
20                _x ="_x", _y_r_y_o = ["_y.r", "_y.o"];
21
22        df.multirec = function(
23                                        /*Function|String|Array*/ cond,
24                                        /*Function|String|Array*/ then,
25                                        /*Function|String|Array*/ before,
26                                        /*Function|String|Array*/ after){
27                // summary:
28                //              Generates a function for the multi-way recursion pattern.
29                //              All parameter functions are called in the context of "this" object.
30                // cond:
31                //              The lambda expression, which is used to detect the termination of recursion.
32                //              It accepts the same parameter as the generated recursive function itself.
33                //              This function should return "true", if the recursion should be stopped,
34                //              and the "then" part should be executed. Otherwise the recursion will proceed.
35                // then:
36                //              The lambda expression, which is called upon termination of the recursion.
37                //              It accepts the same parameters as the generated recursive function itself.
38                //              The returned value will be returned as the value of the generated function.
39                // before:
40                //              The lambda expression, which is called before the recursive step.
41                //              It accepts the same parameter as the generated recursive function itself.
42                //              The returned value should be an array, which is used to call
43                //              the generated function recursively. Each member of the array should be
44                //              an array of parameters. The length of it defines how many times
45                //              the generated function is called recursively.
46                // above:
47                //              The lambda expression, which is called after the recursive step.
48                //              It accepts two parameters: the array of returned values from recursive steps,
49                //              and the original array of parameters used with all other functions.
50                //              The returned value will be returned as the value of the generated function.
51
52                var c, t, b, a, cs, ts, bs, as, dict1 = {}, dict2 = {},
53                        add2dict = function(x){ dict1[x] = 1; };
54                if(typeof cond == "string"){
55                        cs = inline(cond, _x, add2dict);
56                }else{
57                        c = df.lambda(cond);
58                        cs = "_c.apply(this, _x)";
59                        dict2["_c=_t.c"] = 1;
60                }
61                if(typeof then == "string"){
62                        ts = inline(then, _x, add2dict);
63                }else{
64                        t = df.lambda(then);
65                        ts = "_t.apply(this, _x)";
66                }
67                if(typeof before == "string"){
68                        bs = inline(before, _x, add2dict);
69                }else{
70                        b = df.lambda(before);
71                        bs = "_b.apply(this, _x)";
72                        dict2["_b=_t.b"] = 1;
73                }
74                if(typeof after == "string"){
75                        as = inline(after, _y_r_y_o, add2dict);
76                }else{
77                        a = df.lambda(after);
78                        as = "_a.call(this, _y.r, _y.o)";
79                        dict2["_a=_t.a"] = 1;
80                }
81                var locals1 = df.keys(dict1), locals2 = df.keys(dict2),
82                        f = new Function([], "var _y={a:arguments},_x,_r,_z,_i".concat( // Function
83                                locals1.length ? "," + locals1.join(",") : "",
84                                locals2.length ? ",_t=arguments.callee," + locals2.join(",") : "",
85                                t ? (locals2.length ? ",_t=_t.t" : "_t=arguments.callee.t") : "",
86                                ";for(;;){for(;;){if(_y.o){_r=",
87                                as,
88                                ";break}_x=_y.a;if(",
89                                cs,
90                                "){_r=",
91                                ts,
92                                ";break}_y.o=_x;_x=",
93                                bs,
94                                ";_y.r=[];_z=_y;for(_i=_x.length-1;_i>=0;--_i){_y={p:_y,a:_x[_i],z:_z}}}if(!(_z=_y.z)){return _r}_z.r.push(_r);_y=_y.p}"
95                        ));
96                if(c){ f.c = c; }
97                if(t){ f.t = t; }
98                if(b){ f.b = b; }
99                if(a){ f.a = a; }
100                return f;
101        };
102})();
103
104/*
105For documentation only:
106
1071) The original recursive version:
108
109var multirec1 = function(cond, then, before, after){
110        var cond   = df.lambda(cond),
111                then   = df.lambda(then),
112                before = df.lambda(before),
113                after  = df.lambda(after);
114        return function(){
115                if(cond.apply(this, arguments)){
116                        return then.apply(this, arguments);
117                }
118                var args = before.apply(this, arguments),
119                        ret  = new Array(args.length);
120                for(var i = 0; i < args.length; ++i){
121                        ret[i] = arguments.callee.apply(this, args[i]);
122                }
123                return after.call(this, ret, arguments);
124        };
125};
126
1272) The original iterative version (before minification and inlining):
128
129var multirec2 = function(cond, then, before, after){
130        var cond   = df.lambda(cond),
131                then   = df.lambda(then),
132                before = df.lambda(before),
133                after  = df.lambda(after);
134        return function(){
135                var top = {args: arguments}, args, ret, parent, i;
136                for(;;){
137                        for(;;){
138                                if(top.old){
139                                        ret = after.call(this, top.ret, top.old);
140                                        break;
141                                }
142                                args = top.args;
143                                if(cond.apply(this, args)){
144                                        ret = then.apply(this, args);
145                                        break;
146                                }
147                                top.old = args;
148                                args = before.apply(this, args);
149                                top.ret = [];
150                                parent = top;
151                                for(i = args.length - 1; i >= 0; --i){
152                                        top = {prev: top, args: args[i], parent: parent};
153                                }
154                        }
155                        if(!(parent = top.parent)){
156                                return ret;
157                        }
158                        parent.ret.push(ret);
159                        top = top.prev;
160                }
161        };
162};
163
164*/
Note: See TracBrowser for help on using the repository browser.