source: Dev/branches/rest-dojo-ui/client/dojox/lang/functional/binrec.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.2 KB
Line 
1dojo.provide("dojox.lang.functional.binrec");
2
3dojo.require("dojox.lang.functional.lambda");
4dojo.require("dojox.lang.functional.util");
5
6// This module provides recursion combinators:
7//      - a binary 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", _z_r_r_z_a = ["_z.r", "_r", "_z.a"];
21
22        df.binrec = 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 binary 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 of two variable, which are used to call
43                //              the generated function recursively twice in row starting from the first item.
44                // above:
45                //              The lambda expression, which is called after the recursive step.
46                //              It accepts three parameters: two returned values from recursive steps, and
47                //              the original array of parameters used with all other functions.
48                //              The returned value will be returned as the value of the generated function.
49
50                var c, t, b, a, cs, ts, bs, as, dict1 = {}, dict2 = {},
51                        add2dict = function(x){ dict1[x] = 1; };
52                if(typeof cond == "string"){
53                        cs = inline(cond, _x, add2dict);
54                }else{
55                        c = df.lambda(cond);
56                        cs = "_c.apply(this, _x)";
57                        dict2["_c=_t.c"] = 1;
58                }
59                if(typeof then == "string"){
60                        ts = inline(then, _x, add2dict);
61                }else{
62                        t = df.lambda(then);
63                        ts = "_t.apply(this, _x)";
64                }
65                if(typeof before == "string"){
66                        bs = inline(before, _x, add2dict);
67                }else{
68                        b = df.lambda(before);
69                        bs = "_b.apply(this, _x)";
70                        dict2["_b=_t.b"] = 1;
71                }
72                if(typeof after == "string"){
73                        as = inline(after, _z_r_r_z_a, add2dict);
74                }else{
75                        a = df.lambda(after);
76                        as = "_a.call(this, _z.r, _r, _z.a)";
77                        dict2["_a=_t.a"] = 1;
78                }
79                var locals1 = df.keys(dict1), locals2 = df.keys(dict2),
80                        f = new Function([], "var _x=arguments,_y,_z,_r".concat(        // Function
81                                locals1.length ? "," + locals1.join(",") : "",
82                                locals2.length ? ",_t=_x.callee," + locals2.join(",") : "",
83                                t ? (locals2.length ? ",_t=_t.t" : "_t=_x.callee.t") : "",
84                                ";while(!",
85                                cs,
86                                "){_r=",
87                                bs,
88                                ";_y={p:_y,a:_r[1]};_z={p:_z,a:_x};_x=_r[0]}for(;;){do{_r=",
89                                ts,
90                                ";if(!_z)return _r;while(\"r\" in _z){_r=",
91                                as,
92                                ";if(!(_z=_z.p))return _r}_z.r=_r;_x=_y.a;_y=_y.p}while(",
93                                cs,
94                                ");do{_r=",
95                                bs,
96                                ";_y={p:_y,a:_r[1]};_z={p:_z,a:_x};_x=_r[0]}while(!",
97                                cs,
98                                ")}"
99                        ));
100                if(c){ f.c = c; }
101                if(t){ f.t = t; }
102                if(b){ f.b = b; }
103                if(a){ f.a = a; }
104                return f;
105        };
106})();
107
108/*
109For documentation only:
110
1111) The original recursive version:
112
113var binrec1 = function(cond, then, before, after){
114        var cond   = df.lambda(cond),
115                then   = df.lambda(then),
116                before = df.lambda(before),
117                after  = df.lambda(after);
118        return function(){
119                if(cond.apply(this, arguments)){
120                        return then.apply(this, arguments);
121                }
122                var args = before.apply(this, arguments);
123                var ret1 = arguments.callee.apply(this, args[0]);
124                var ret2 = arguments.callee.apply(this, args[1]);
125                return after.call(this, ret1, ret2, arguments);
126        };
127};
128
1292) The original iterative version (before minification and inlining):
130
131var binrec2 = function(cond, then, before, after){
132        var cond   = df.lambda(cond),
133                then   = df.lambda(then),
134                before = df.lambda(before),
135                after  = df.lambda(after);
136        return function(){
137                var top1, top2, ret, args = arguments;
138                // first part: start the pump
139                while(!cond.apply(this, args)){
140                        ret = before.apply(this, args);
141                        top1 = {prev: top1, args: ret[1]};
142                        top2 = {prev: top2, args: args};
143                        args = ret[0];
144                }
145                for(;;){
146                        // second part: mop up
147                        do{
148                                ret = then.apply(this, args);
149                                if(!top2){
150                                        return ret;
151                                }
152                                while("ret" in top2){
153                                        ret = after.call(this, top2.ret, ret, top2.args);
154                                        if(!(top2 = top2.prev)){
155                                                return ret;
156                                        }
157                                }
158                                top2.ret = ret;
159                                args = top1.args;
160                                top1 = top1.prev;
161                        }while(cond.apply(this, args));
162                        // first part (encore)
163                        do{
164                                ret = before.apply(this, args);
165                                top1 = {prev: top1, args: ret[1]};
166                                top2 = {prev: top2, args: args};
167                                args = ret[0];
168                        }while(!cond.apply(this, args));
169                }
170        };
171};
172
173*/
Note: See TracBrowser for help on using the repository browser.