mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
69 lines
3.9 KiB
C
69 lines
3.9 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/macros.internal.h"
|
|
#include "third_party/lua/cosmo.h"
|
|
#include "third_party/lua/lauxlib.h"
|
|
|
|
// calling convention for lua stack of L is:
|
|
// -2 is function
|
|
// -1 is is argument (assuming nargs == 1)
|
|
// L will have this after the call
|
|
// -1 is error or result (assuming nres == 1)
|
|
// @param L is main Lua interpreter
|
|
// @note this needs to be reentrant
|
|
int LuaCallWithTrace(lua_State *L, int nargs, int nres, lua_State *C) {
|
|
int nresults, status;
|
|
bool canyield = !!C; // allow yield if coroutine is provided
|
|
if (!C) C = lua_newthread(L); // create a new coroutine if not passed
|
|
// move coroutine to the bottom of the stack (including one that is passed)
|
|
lua_insert(L, 1);
|
|
// make sure that there is enough stack space
|
|
if (!lua_checkstack(C, 1 + nargs)) {
|
|
lua_pushliteral(L, "too many arguments to resume");
|
|
return LUA_ERRRUN; /* error flag */
|
|
}
|
|
// move the function (and arguments) to the top of the coro stack
|
|
lua_xmove(L, C, 1 + nargs);
|
|
// resume the coroutine thus executing the function
|
|
status = lua_resume(C, L, nargs, &nresults);
|
|
// remove coroutine (still) at the bottom, but only if not yielding
|
|
// keep it when yielding to anchor, so it's not GC-collected
|
|
// it's going to be removed at the beggining of the request handling
|
|
if (!canyield) lua_remove(L, 1);
|
|
if (status != LUA_OK && status != LUA_YIELD) {
|
|
// move the error message
|
|
lua_xmove(C, L, 1);
|
|
// replace the error with the traceback on failure
|
|
luaL_traceback2(L, C, lua_tostring(L, -1), 0);
|
|
lua_remove(L, -2); // remove the error message
|
|
} else {
|
|
if (!lua_checkstack(L, MAX(nresults, nres))) {
|
|
lua_pop(C, nresults); /* remove results anyway */
|
|
lua_pushliteral(L, "too many results to resume");
|
|
return LUA_ERRRUN; /* error flag */
|
|
}
|
|
lua_xmove(C, L, nresults); // move results to the main stack
|
|
// grow the stack in case returned fewer results
|
|
// than the caller expects, as lua_resume
|
|
// doesn't adjust the stack for needed results
|
|
for (; nresults < nres; nresults++) lua_pushnil(L);
|
|
if (!canyield) status = LUA_OK; // treat LUA_YIELD the same as LUA_OK
|
|
}
|
|
return status;
|
|
}
|