Skip to content

Latest commit

 

History

History
82 lines (66 loc) · 2.2 KB

File metadata and controls

82 lines (66 loc) · 2.2 KB

Asynchronous Generators and Fibers

How does it Work?

To make a function resummable, I need to transform the function into a form that can be resumed. So I have to maintain the state of the function, and when you call the function again, it will resume from that state.

So I have to turn a function from something that looks like this:

function hello()
{
    @yield "a";
    @yield "b";
    @yield "c";
}

Into a function that looks something like this:

function hello()
{
    var __state = 0;
    var __current;
    function __run()
    {
        while (true) switch (__state)
        {
            case -1:
                throw "function ended";
            case 0:
                __current = "a";
                __state = 1;
                return;
            case 1:
                __current = "b";
                __state = 2;
                return;
            case 2:
                __current = "c";
                __state = -1;
                return;
            case _:
                throw "invalid state";
        }
        ++_state;
    }
    return { hasNext: ... , next: ... , send: ... };
}

It gets tricky when there are various control structures, scoping, and variable declarations. So what I did was to hoist all variables to above the __run function, and I transformed all control structures (that contains @yield) into a flattened one by adding @label x and @goto x annotations. Due to the flattened code, variable names need to be renamed so they don't clash, since they're all within a single scope.

Since @yield is also an expression, it can have a value (via send).

So something like:

foo(a, bar(), @yield 123);

Have to be transformed into (to maintain execution order):

var a0 = a;
var a1 = bar();
var a2 = @yield 123;
foo(a0, a1, a2);

Before it becomes:

var a0 = a;
var a1 = bar();
var a2 = { __current = 123; @state next; return; @label next; __yielded; };
foo(a0, a1, a2);

All the scopes will then be merged and flattened, and cut up into switch cases at every @label.

Here's an example of all the transformations that a fibonacci function goes through.