File: coroutine.js

package info (click to toggle)
conkeror 0.9~git080629-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 1,132 kB
  • ctags: 906
  • sloc: sh: 340; ansic: 246; xml: 105; makefile: 77
file content (124 lines) | stat: -rw-r--r-- 2,986 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
 * (C) Copyright 2008 Jeremy Maitin-Shepard
 *
 * Use, modification, and distribution are subject to the terms specified in the
 * COPYING file.
**/

function _return_value(x) {
    this.value = x;
}

function co_return(x) {
    return new _return_value(x);
}

const CONTINUATION = { toString: function () "[object CONTINUATION]" };
const SUSPEND = { toString: function () "[object SUSPEND]" };

function is_coroutine(obj) {
    return obj != null &&
        typeof(obj) == "object" &&
        typeof(obj.next) == "function" &&
        typeof(obj.send) == "function";
}

function _do_call(f) {
    var cc = yield;

    var stack = [];
    var y = undefined;
    var throw_value = false;
    while (true) {
        try {
            let x;
            if (throw_value) {
                throw_value = false;
                x = f.throw(y);
            }
            else
                x = f.send(y);

            if (x == CONTINUATION) {
                y = cc;
                continue;
            }

            if (x === SUSPEND) {
                try {
                    x = yield;
                    y = x;
                } catch (e) {
                    throw_value = true;
                    y = e;
                }
                continue;
            }

            if (is_coroutine(x))
            {
                stack[stack.length] = f;
                f = x;
                y = undefined;
                continue;
            }

            if (x instanceof _return_value) {
                if (stack.length == 0)
                    return;
                f.close();
                f = stack[stack.length - 1];
                stack.length--;
                y = x.value;
                continue;
            }

            // Just return the value back to the function
            y = x;
        } catch (e) {
            if (stack.length == 0)
                return;
            f = stack[stack.length - 1];
            stack.length--;
            if (e instanceof StopIteration)
                y = undefined;
            else {
                y = e;
                throw_value = true;
            }
        }
    }
}

function co_call(f) {
    if (!is_coroutine(f))
        return;
    var g = _do_call(f);
    g.next();
    var cc = function (x) {
        try {
            g.send(x);
        } catch (e if e instanceof StopIteration) {}
        catch (e) {
            // Dump this error, because it indicates a programming error
            dump_error(e);
        }
    };
    cc.throw = function (x) {
        try {
            g.throw(x);
        } catch (e if e instanceof StopIteration) {}
        catch (e) {
            // Dump this error, because it indicates a programming error
            dump_error(e);
        }
    };
    try {
        g.send(cc);
    } catch (e if e instanceof StopIteration) {}
    catch (e) {
        // Dump this error, because it indicates a programming error
        dump_error(e);
    }
    return cc;
}