summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lapi.js8
-rw-r--r--src/lcorolib.js72
-rw-r--r--tests/lcorolib.js50
3 files changed, 126 insertions, 4 deletions
diff --git a/src/lapi.js b/src/lapi.js
index 2f2802f..c841ba2 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -279,6 +279,13 @@ const lua_pushlightuserdata = function(L, p) {
assert(L.top <= L.ci.top, "stack overflow");
};
+const lua_pushthread = function(L) {
+ L.stack[L.top++] = L;
+ assert(L.top <= L.ci.top, "stack overflow");
+
+ return L.l_G.mainthread === L;
+};
+
const lua_pushglobaltable = function(L) {
lua_rawgeti(L, lua.LUA_REGISTRYINDEX, lua.LUA_RIDX_GLOBALS);
};
@@ -746,6 +753,7 @@ module.exports.lua_pushlstring = lua_pushlstring;
module.exports.lua_pushnil = lua_pushnil;
module.exports.lua_pushnumber = lua_pushnumber;
module.exports.lua_pushstring = lua_pushstring;
+module.exports.lua_pushthread = lua_pushthread;
module.exports.lua_pushvalue = lua_pushvalue;
module.exports.lua_rawequal = lua_rawequal;
module.exports.lua_rawget = lua_rawget;
diff --git a/src/lcorolib.js b/src/lcorolib.js
index 73699a7..b595d4d 100644
--- a/src/lcorolib.js
+++ b/src/lcorolib.js
@@ -8,6 +8,7 @@ const lapi = require('./lapi.js');
const lauxlib = require('./lauxlib.js');
const lstate = require('./lstate.js');
const ldo = require('./ldo.js');
+const ldebug = require('./ldebug.js');
const CT = lua.constant_types;
const TS = lua.thread_status;
@@ -46,7 +47,7 @@ const auxresume = function(L, co, narg) {
}
};
-const luaB_resume = function(L) {
+const luaB_coresume = function(L) {
let co = getco(L);
let r = auxresume(L, co, lapi.lua_gettop(L) - 1);
if (r < 0) {
@@ -60,6 +61,22 @@ const luaB_resume = function(L) {
}
};
+const luaB_auxwrap = function(L) {
+ let co = lapi.lua_tothread(L, lapi.lua_upvalueindex(1));
+ let r = auxresume(L, co, lapi.lua_gettop(L));
+ if (r < 0) {
+ if (lapi.lua_type(L, -1) === CT.LUA_TSTRING) { /* error object is a string? */
+ lauxlib.luaL_where(L, 1); /* add extra info */
+ lapi.lua_insert(L, -2);
+ lapi.lua_concat(L, 2);
+ }
+
+ return lapi.lua_error(L); /* propagate error */
+ }
+
+ return r;
+};
+
const luaB_cocreate = function(L) {
lauxlib.luaL_checktype(L, 1, CT.LUA_TFUNCTION);
let NL = lstate.lua_newthread(L);
@@ -68,14 +85,61 @@ const luaB_cocreate = function(L) {
return 1;
};
+const luaB_cowrap = function(L) {
+ luaB_cocreate(L);
+ lapi.lua_pushcclosure(L, luaB_auxwrap, 1);
+ return 1;
+};
+
const luaB_yield = function(L) {
return ldo.lua_yield(L, lapi.lua_gettop(L));
};
+const luaB_costatus = function(L) {
+ let co = getco(L);
+ if (L === co) lapi.lua_pushliteral(L, "running");
+ else {
+ switch (lapi.lua_status(co)) {
+ case TS.LUA_YIELD:
+ lapi.lua_pushliteral(L, "suspended");
+ break;
+ case TS.LUA_OK: {
+ let ar = new lua.lua_Debug();
+ if (ldebug.lua_getstack(co, 0, ar) > 0) /* does it have frames? */
+ lapi.lua_pushliteral(L, "normal"); /* it is running */
+ else if (lapi.lua_gettop(co) === 0)
+ lapi.lua_pushliteral(L, "dead");
+ else
+ lapi.lua_pushliteral(L, "suspended"); /* initial state */
+ break;
+ }
+ default: /* some error occurred */
+ lapi.lua_pushliteral(L, "dead");
+ break;
+ }
+ }
+
+ return 1;
+};
+
+const luaB_yieldable = function(L) {
+ lapi.lua_pushboolean(L, lapi.lua_isyieldable(L));
+ return 1;
+};
+
+const luaB_corunning = function(L) {
+ lapi.lua_pushboolean(L, lapi.lua_pushthread(L));
+ return 2;
+};
+
const co_funcs = {
- "create": luaB_cocreate,
- "yield": luaB_yield,
- "resume": luaB_resume
+ "create": luaB_cocreate,
+ "isyieldable": luaB_yieldable,
+ "resume": luaB_coresume,
+ "running": luaB_corunning,
+ "status": luaB_costatus,
+ "wrap": luaB_cowrap,
+ "yield": luaB_yield
};
const luaopen_coroutine = function(L) {
diff --git a/tests/lcorolib.js b/tests/lcorolib.js
index 6b48912..400e721 100644
--- a/tests/lcorolib.js
+++ b/tests/lcorolib.js
@@ -16,6 +16,7 @@ const lua = require('../src/lua.js');
const linit = require('../src/linit.js');
const CT = lua.constant_types;
+
test('simple coroutine', function (t) {
let luaCode = `
local co = coroutine.create(function (start)
@@ -50,4 +51,53 @@ test('simple coroutine', function (t) {
625,
"Correct element(s) on the stack"
);
+});
+
+
+test('simple coroutine', function (t) {
+ let luaCode = `
+ local co = coroutine.create(function (start)
+ local b = coroutine.yield(start * start);
+ coroutine.yield(b * b)
+ end)
+
+ local s1 = coroutine.status(co)
+
+ local success, pow = coroutine.resume(co, 5)
+ success, pow = coroutine.resume(co, pow)
+
+ coroutine.resume(co, pow)
+
+ local s2 = coroutine.status(co)
+
+ return s1, s2
+ `, L;
+
+ t.plan(3);
+
+ // t.doesNotThrow(function () {
+
+ let bc = toByteCode(luaCode).dataView;
+
+ L = lauxlib.luaL_newstate();
+
+ linit.luaL_openlibs(L);
+
+ lapi.lua_load(L, bc, "test-coroutine");
+
+ lapi.lua_call(L, 0, -1);
+
+ // }, "JS Lua program ran without error");
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -2),
+ "suspended",
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -1),
+ "dead",
+ "Correct element(s) on the stack"
+ );
}); \ No newline at end of file