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

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

Added Dojo 1.9.3 release.

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// Acknowledgements:
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.