2021-02-25 14:58:29 -05:00
|
|
|
#include <cstring>
|
2021-01-02 13:31:18 -05:00
|
|
|
#include "traceback.hpp"
|
|
|
|
|
|
|
|
|
|
#define TRACEBACK_LEVELS1 12
|
|
|
|
|
#define TRACEBACK_LEVELS2 10
|
|
|
|
|
|
|
|
|
|
|
2021-02-17 13:38:22 -05:00
|
|
|
// Call this with the error message on top of the stack.
|
2021-02-20 19:17:20 -05:00
|
|
|
// The error message is replaced with a traceback.
|
|
|
|
|
//
|
|
|
|
|
int traceback_coroutine(lua_State *L) {
|
2021-06-03 13:29:19 -04:00
|
|
|
lua_checkstack(L, 20);
|
2021-01-02 13:31:18 -05:00
|
|
|
int top = lua_gettop(L);
|
|
|
|
|
|
2021-02-17 13:38:22 -05:00
|
|
|
// Convert message to a string
|
|
|
|
|
if (!lua_tostring(L, top)) {
|
|
|
|
|
luaL_callmeta(L, top, "__tostring");
|
|
|
|
|
// If callmeta didn't produce exactly one string, clear the stack
|
|
|
|
|
// and push "unknown error"
|
|
|
|
|
if ((lua_gettop(L) == top + 1) && (lua_tostring(L, -1))) {
|
|
|
|
|
lua_remove(L, top);
|
|
|
|
|
} else {
|
|
|
|
|
lua_settop(L, top - 1);
|
|
|
|
|
lua_pushstring(L, "unknown error");
|
|
|
|
|
}
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Append the traceback.
|
|
|
|
|
lua_Debug ar;
|
|
|
|
|
int firstpart = 1;
|
2021-02-25 14:58:29 -05:00
|
|
|
bool any = false;
|
2021-02-20 19:17:20 -05:00
|
|
|
for (int level = 0; lua_getstack(L, level, &ar); level++) {
|
2021-01-02 13:31:18 -05:00
|
|
|
if (level > TRACEBACK_LEVELS1 && firstpart) {
|
|
|
|
|
/* no more than `LEVELS2' more levels? */
|
2021-02-20 19:17:20 -05:00
|
|
|
if (!lua_getstack(L, level + TRACEBACK_LEVELS2, &ar))
|
2021-01-02 13:31:18 -05:00
|
|
|
level--; /* keep going */
|
|
|
|
|
else {
|
|
|
|
|
lua_pushliteral(L, "\n\t..."); /* too many levels */
|
2021-02-20 19:17:20 -05:00
|
|
|
while (lua_getstack(L, level + TRACEBACK_LEVELS2, &ar)) /* find last levels */
|
2021-01-02 13:31:18 -05:00
|
|
|
level++;
|
|
|
|
|
}
|
|
|
|
|
firstpart = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-02-20 19:17:20 -05:00
|
|
|
lua_getinfo(L, "Snl", &ar);
|
2021-02-25 14:58:29 -05:00
|
|
|
if ((!any) && (*ar.what == 'C') && (ar.name != 0)) {
|
|
|
|
|
if (strcmp(ar.name, "__newindex") == 0) continue;
|
2021-02-20 19:17:20 -05:00
|
|
|
}
|
2021-01-02 13:31:18 -05:00
|
|
|
if ((ar.currentline > 0) || (*ar.namewhat != 0) || (*ar.what != 'C')) {
|
2021-02-25 14:58:29 -05:00
|
|
|
any = true;
|
2021-01-02 13:31:18 -05:00
|
|
|
lua_pushliteral(L, "\n\t");
|
|
|
|
|
lua_pushfstring(L, "%s:", ar.short_src);
|
|
|
|
|
if (ar.currentline > 0)
|
|
|
|
|
lua_pushfstring(L, "%d:", ar.currentline);
|
|
|
|
|
if (*ar.namewhat != '\0') /* is there a name? */
|
|
|
|
|
lua_pushfstring(L, " in function " LUA_QS, ar.name);
|
|
|
|
|
else {
|
|
|
|
|
if (*ar.what == 'm') /* main? */
|
|
|
|
|
lua_pushfstring(L, " in main chunk");
|
|
|
|
|
else if (*ar.what == 'C' || *ar.what == 't')
|
|
|
|
|
lua_pushliteral(L, " ?"); /* C function or tail call */
|
|
|
|
|
else
|
|
|
|
|
lua_pushfstring(L, " in function <%s:%d>",
|
|
|
|
|
ar.short_src, ar.linedefined);
|
|
|
|
|
}
|
2021-02-17 13:38:22 -05:00
|
|
|
if (1 + lua_gettop(L) - top > 5) {
|
|
|
|
|
lua_concat(L, 1 + lua_gettop(L) - top);
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_pushstring(L, "\n");
|
2021-02-17 13:38:22 -05:00
|
|
|
if (1 + lua_gettop(L) - top > 1) {
|
|
|
|
|
lua_concat(L, 1 + lua_gettop(L) - top);
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
2021-02-17 13:38:22 -05:00
|
|
|
return 1;
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int traceback_pcall(lua_State *L, int narg, int nret) {
|
|
|
|
|
int status;
|
|
|
|
|
int base = lua_gettop(L) - narg; /* function index */
|
2021-02-20 19:17:20 -05:00
|
|
|
lua_pushcfunction(L, traceback_coroutine); /* push traceback function */
|
2021-01-02 13:31:18 -05:00
|
|
|
lua_insert(L, base); /* put it under chunk and args */
|
|
|
|
|
status = lua_pcall(L, narg, nret, base);
|
|
|
|
|
lua_remove(L, base); /* remove traceback function */
|
|
|
|
|
return status;
|
|
|
|
|
}
|