Macro-based coroutines for Haxe.
See the pecan
manual for documentation.
Macro-based coroutines for Haxe
Home Page: https://aurel300.github.io/pecan/
Macro-based coroutines for Haxe.
See the pecan
manual for documentation.
Currently, the "instruction pointer" is an Array<Int>
, indicating the nested action index within arrays of CoAction
. It would be better to perform code flow analysis to turn all CoAction
s into a single array/Vector
with the action + the index of the next action (conditionals and loops would have two indices for branching). This should simplify the implementation of the coroutine runner, simplify CoAction
, etc.
entryPosition
variablesAdd a way for macros to use pecan without the default API (self
, suspend
, terminate
, etc). Could be an extra argument on CoContext.build
.
It should be possible to declare coroutines as class methods:
class Foo {
@:pecan.co static function bar(x:String) {
trace("hello");
suspend();
trace(x);
}
public static function main():Void {
var c = bar.run("world");
c.tick(); // hello
c.wakeup(); // world
}
}
The return type of the function can be used as the type for yields
. The accept
type must be declared as an argument to the :pecan.co
metadata (since the function arguments are arguments to the run
call).
Allow a more function-like syntax for coroutine declarations:
var c = co((foo, bar) -> {
trace('called with arguments $foo and $bar');
});
c.run("foo", "bar").tick();
For type-safety, a different type should be defined for each coroutine factory, with an appropriate run
method.
co.state
should indicate when the coroutine exited due to an unhandled exception.
Allow an accept
call in any expression, unfold as necessary:
var foo = accept() + accept();
Transform into:
Accept((self, value) -> self.vars._tmp1 = value),
Accept((self, value) -> self.vars._tmp2 = value),
Sync((self) -> self.vars.foo = self.vars._tmp1 + self.vars_tmp2)
co({
label("start");
yield("starting...");
label("repeat");
yield("repeating...");
goto("repeat");
}, null, (_:String));
Looks much more awkward than a regular loop, but a coroutine can be moved to an arbitrary label externally. Would be useful to manage e.g. the state machines of enemy AI. Could also make it more practical to hot-plug coroutines or have coroutine "interfaces" based on labels.
#3 should be implemented first, so a label is indexed with a single integer.
Spotted a minor error - nothing that anyone trying this out wouldn't figure out, but anyway...
var factory = pecan.Co.co({ // (1)
var greeted = 0;
trace("Greeter online!");
suspend(); // (2)
while (true) { // (3)
var name = accept(); // (4)
if (name == null)
break;
trace('Hello, $name!');
yield(++greeted); // (5)
}
trace("Bye!");
}, (_ : String), (_ : Int)); // (6)
var instance = co.run(); // (7) <---- should be factory.run()
Type annotations are currently required for I/O and returns. This is because the type of the coroutine instance must be available while typing its body. This should be avoidable with a better choice of arguments in CoContext.typeExpr
(since access to these is replaced anyway).
@:pecan.accept function sync(?ret:pecan.Void->Void, ?co:pecan.ICo<Any, Any, Any>):pecan.Void {
ret(Void);
return null;
}
@:pecan.accept function async(?ret:pecan.Void->Void, ?co:pecan.ICo<Any, Any, Any>):pecan.Void {
haxe.Timer.delay(() -> ret(Void), 10);
return null;
}
function main() {
pecan.Co.co({
sync();
trace("hallo");
async();
}).run();
}
Output:
src/Main.hx:14: hallo
src/Main.hx:14: hallo
yield
, accept
, etc. are currently magical calls that will always shadow variables or functions with the same name. It might be better to instead make these static functions of pecan.Co
, then resolve them similarly to #5.
Allow array and map comprehension of suspending loops:
var foo = [ for (i in 0...3) accept() ];
Transform into:
var foo = [];
for (i in 0...3) foo.push(accept());
Ideally #1 should be implemented first so foo.push(accept());
is not a special case.
Macro-in-macro forbids the following syntax:
class MyCo extends pecan.Co {
@:co.suspend function wait(delay:Int, wakeup:()->Void):Void {
haxe.Timer.delay(delay, wakeup);
}
}
There should still be a convenient way to declare wrappers over co
which define their own suspending functions:
// (in macro context)
class MyCo {
public static function co(block:Expr, tin:Expr, tout:Expr):Expr {
return pecan.Co.wrap(macro class MyCoFunctions {
@:co.suspend function wait(delay:Int, wakeup:()->Void):Void {
haxe.Timer.delay(delay, wakeup);
}
}, block, tin, tout);
}
}
Then used with:
MyCo.co({
trace("a");
wait(200);
trace("b");
});
It should be possible to automatically generate the Haxe de/serialisation methods for a coroutine. It should be enough to store:
As an optimisation, only the state-crossing locals which are actually read by reachable states could be stored.
Serialisation of a coroutine that depends on a closure-captured variable should probably be forbidden as well.
what's the difference between pecan and tink_await?
it seems tink_await is simple than pecan ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.