coroutine.js: make co_call return the continuation
[conkeror.git] / modules / coroutine.js
blobf59ee7d94a980ae9b24bd0a4f15ee913d008bf31
2 function _return_value(x) {
3     this.value = x;
6 function co_return(x) {
7     return new _return_value(x);
10 const CONTINUATION = { toString: function () "[object CONTINUATION]" };
11 const SUSPEND = { toString: function () "[object SUSPEND]" };
13 function is_coroutine(obj) {
14     return obj != null &&
15         typeof(obj) == "object" &&
16         typeof(obj.next) == "function" &&
17         typeof(obj.send) == "function";
20 function _do_call(f) {
21     var cc = yield;
22     
23     var stack = [];
24     var y = undefined;
25     var throw_value = false;
26     while (true) {
27         try {
28             let x;
29             if (throw_value) {
30                 throw_value = false;
31                 x = f.throw(y);
32             }
33             else
34                 x = f.send(y);
36             if (x == CONTINUATION) {
37                 y = cc;
38                 continue;
39             }
41             if (x === SUSPEND) {
42                 try {
43                     x = yield;
44                     y = x;
45                 } catch (e) {
46                     throw_value = true;
47                     y = e;
48                 }
49                 continue;
50             }
52             if (is_coroutine(x))
53             {
54                 stack[stack.length] = f;
55                 f = x;
56                 y = undefined;
57                 continue;
58             }
60             if (x instanceof _return_value) {
61                 if (stack.length == 0)
62                     return;
63                 f.close();
64                 f = stack[stack.length - 1];
65                 stack.length--;
66                 y = x.value;
67                 continue;
68             }
70             // Just return the value back to the function
71             y = x;
72         } catch (e) {
73             if (stack.length == 0)
74                 return;
75             f = stack[stack.length - 1];
76             stack.length--;
77             if (e instanceof StopIteration)
78                 y = undefined;
79             else {
80                 y = e;
81                 throw_value = true;
82             }
83         }
84     }
87 function co_call(f) {
88     if (!is_coroutine(f))
89         return;
90     var g = _do_call(f);
91     g.next();
92     var cc = function (x) {
93         try {
94             g.send(x);
95         } catch (e if e instanceof StopIteration) {}
96     };
97     cc.throw = function (x) {
98         try {
99             g.throw(x);
100         } catch (e if e instanceof StopIteration) {}
101     };
102     try {
103         g.send(cc);
104     } catch (e if e instanceof StopIteration) {}
105     return cc;