From 62cb8279094fd137ce2382fe99592ef0aae0f557 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Thu, 16 Feb 2017 16:04:03 +0100 Subject: lua_call --- src/lapi.js | 31 ++++++++++++++++++++++++++++--- src/ldo.js | 46 ++++++++++++++++++++++++++++++++++++++++++---- tests/C/Makefile | 3 ++- tests/C/lua_call.c | 28 ++++++++++++++++++++++++++++ tests/lapi.js | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 tests/C/lua_call.c diff --git a/src/lapi.js b/src/lapi.js index ee976e1..99955a3 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -219,10 +219,33 @@ const lua_typename = function(L, t) { ** 'load' and 'call' functions (run Lua code) */ +const lua_callk = function(L, nargs, nresults, ctx, k) { + assert(k === null || !(L.ci.callstatus & CIST_LUA), "cannot use continuations inside hooks"); + assert(nargs + 1 < L.top - L.ci.funcOff, "not enough elements in the stack"); + assert(L.status === TS.LUA_OK, "cannot do calls on non-normal thread"); + assert(nargs === lua.LUA_MULTRET || (L.ci.top - L.top >= nargs - nresults, "results from function overflow current stack size")); + + let func = L.top - (nargs + 1); + if (k !== null && L.nny === 0) { /* need to prepare continuation? */ + L.ci.u.c.k = k; + L.ci.u.c.ctx = ctx; + ldo.luaD_call(L, func, nresults); + } else { /* no continuation or no yieldable */ + ldo.luaD_callnoyield(L, func, nresults); + } + + if (nresults == lua.LUA_MULTRET && L.ci.top < L.top) + L.ci.top = L.top; +}; + +const lua_call = function(L, n, r) { + lua_callk(L, n, r, 0, null); +}; + const lua_pcallk = function(L, nargs, nresults, errfunc, ctx, k) { - assert(nargs + 1 < L.top - L.ci.func, "not enough elements in the stack"); + assert(nargs + 1 < L.top - L.ci.funcOff, "not enough elements in the stack"); assert(L.status === TS.LUA_OK, "cannot do calls on non-normal thread"); - assert(nargs == lua.LUA_MULTRET || (L.ci.top - L.top >= nargs - nresults, "results from function overflow current stack size")); + assert(nargs === lua.LUA_MULTRET || (L.ci.top - L.top >= nargs - nresults, "results from function overflow current stack size")); let c = { func: null, @@ -286,4 +309,6 @@ module.exports.lua_tonumber = lua_tonumber; module.exports.lua_tointeger = lua_tointeger; module.exports.lua_toboolean = lua_toboolean; module.exports.lua_tolstring = lua_tolstring; -module.exports.lua_tostring = lua_tostring; \ No newline at end of file +module.exports.lua_tostring = lua_tostring; +module.exports.lua_callk = lua_callk; +module.exports.lua_call = lua_call; \ No newline at end of file diff --git a/src/ldo.js b/src/ldo.js index aa52b76..f965a47 100644 --- a/src/ldo.js +++ b/src/ldo.js @@ -1,6 +1,8 @@ /*jshint esversion: 6 */ "use strict"; +const assert = require('assert'); + const lua = require('./lua.js'); const lobject = require('./lobject.js'); const lstate = require('./lstate.js'); @@ -15,15 +17,51 @@ const TMS = ltm.TMS; const nil = new TValue(CT.LUA_TNIL, null); +/* +** Prepares a function call: checks the stack, creates a new CallInfo +** entry, fills in the relevant information, calls hook if needed. +** If function is a JS function, does the call, too. (Otherwise, leave +** the execution ('luaV_execute') to the caller, to allow stackless +** calls.) Returns true iff function has been executed (JS function). +*/ const luaD_precall = function(L, off, nresults) { let func = L.stack[off]; let ci; switch(func.type) { - case CT.LUA_TCCL: // JS function ? - throw new Error("LUA_TCCL not implemeted yet"); - case CT.LUA_TLCF: // still JS function ? - throw new Error("LUA_TLCF not implemeted yet"); + case CT.LUA_TCCL: + case CT.LUA_TLCF: { + let f = func.type === CT.LUA_TCCL ? func.f : func.value; + + // next_ci + if (L.ci.next) { + L.ci = L.ci.next; + ci = L.ci; + } else { + ci = new lstate.CallInfo(off); + L.ci.next = ci; + ci.previous = L.ci; + ci.next = null; + + L.ci = ci; + L.ciOff++; + } + + ci.nresults = nresults; + ci.func = func; + ci.funcOff = off; + ci.top = L.top + lua.LUA_MINSTACK; + ci.callstatus = 0; + // TODO: hook + let n = f(L); /* do the actual call */ + + assert(n < L.top - L.ci.funcOff, "not enough elements in the stack"); + + luaD_poscall(L, ci, L.top - n, n); + + return true; + break; + } case CT.LUA_TLCL: { let p = func.p; let n = L.top - off - 1; diff --git a/tests/C/Makefile b/tests/C/Makefile index 357bbbe..816be44 100644 --- a/tests/C/Makefile +++ b/tests/C/Makefile @@ -10,4 +10,5 @@ all: $(CC) $(CFLAGS) $(LIBS) lua_pushstring.c -o lua_pushstring.out $(CC) $(CFLAGS) $(LIBS) lua_pushboolean.c -o lua_pushboolean.out $(CC) $(CFLAGS) $(LIBS) lua_pushvalue.c -o lua_pushvalue.out - $(CC) $(CFLAGS) $(LIBS) lua_pushcclosure-light.c -o lua_pushcclosure-light.out \ No newline at end of file + $(CC) $(CFLAGS) $(LIBS) lua_pushcclosure-light.c -o lua_pushcclosure-light.out + $(CC) $(CFLAGS) $(LIBS) lua_call.c -o lua_call.out \ No newline at end of file diff --git a/tests/C/lua_call.c b/tests/C/lua_call.c new file mode 100644 index 0000000..3e0e406 --- /dev/null +++ b/tests/C/lua_call.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +int func(lua_State *L) { + lua_pushstring(L, "hello"); + return 1; +} + +int main(void) { + + lua_State *L = luaL_newstate(); + + luaL_openlibs(L); + + lua_pushcfunction(L, func); + + lua_call(L, 0, 1); + + printf("Lua returned: %s\n", lua_tostring(L, -1)); + + lua_close(L); + + return 0; + +} \ No newline at end of file diff --git a/tests/lapi.js b/tests/lapi.js index ad39fe1..c0f1cdc 100644 --- a/tests/lapi.js +++ b/tests/lapi.js @@ -278,4 +278,38 @@ test('lua_pushcfunction', function (t) { "function", "Correct element(s) on the stack" ); +}); + + +test('lua_call (calling a light JS function)', function (t) { + let L; + + t.plan(3); + + t.doesNotThrow(function () { + + let fn = function(L) { + lapi.lua_pushstring(L, "hello"); + return 1; + }; + + L = lauxlib.luaL_newstate(); + + lapi.lua_pushcfunction(L, fn); + + lapi.lua_call(L, 0, 1); + + }, "JS Lua program ran without error"); + + t.strictEqual( + lapi.lua_gettop(L), + 1, + "top is correct" + ); + + t.strictEqual( + lapi.lua_tostring(L, -1), + "hello", + "top is correct" + ); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2