source: Dev/trunk/src/client/dojox/lang/functional/binrec.js @ 483

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

Added Dojo 1.9.3 release.

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// 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", _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.