aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lapi.js31
-rw-r--r--src/ldo.js46
-rw-r--r--tests/C/Makefile3
-rw-r--r--tests/C/lua_call.c28
-rw-r--r--tests/lapi.js34
5 files changed, 134 insertions, 8 deletions
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 <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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