Change to coroutine infrastructure
[conkeror.git] / modules / coroutine.js
blob96eb11ab8447926b80514e14f2bd45470f4a2afa
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 typeof(obj) == "object" &&
15         typeof(obj.next) == "function" &&
16         typeof(obj.send) == "function";
19 function _do_call(f) {
20     var cc = yield;
21     
22     var stack = [];
23     var y = undefined;
24     var throw_value = false;
25     while (true) {
26         try {
27             let x;
28             if (throw_value) {
29                 throw_value = false;
30                 x = f.throw(y);
31             }
32             else
33                 x = f.send(y);
35             if (x == CONTINUATION) {
36                 y = cc;
37                 continue;
38             }
40             if (x === SUSPEND) {
41                 try {
42                     x = yield;
43                     y = x;
44                 } catch (e) {
45                     throw_value = true;
46                     y = e;
47                 }
48                 continue;
49             }
51             if (is_coroutine(x))
52             {
53                 stack[stack.length] = f;
54                 f = x;
55                 y = undefined;
56                 continue;
57             }
59             if (x instanceof _return_value) {
60                 if (stack.length == 0)
61                     return;
62                 f.close();
63                 f = stack[stack.length - 1];
64                 stack.length--;
65                 y = x.value;
66                 continue;
67             }
69             // Just return the value back to the function
70             y = x;
71         } catch (e) {
72             if (stack.length == 0)
73                 return;
74             f = stack[stack.length - 1];
75             stack.length--;
76             if (e instanceof StopIteration)
77                 y = undefined;
78             else {
79                 y = e;
80                 throw_value = true;
81             }
82         }
83     }
86 function co_call(f) {
87     if (!is_coroutine(f))
88         return;
89     var g = _do_call(f);
90     g.next();
91     var cc = function (x) {
92         try {
93             g.send(x);
94         } catch (e if e instanceof StopIteration) {}
95     };
96     cc.throw = function (x) {
97         try {
98             g.throw(x);
99         } catch (e if e instanceof StopIteration) {}
100     };
101     try {
102         g.send(cc);
103     } catch (e if e instanceof StopIteration) {}