|
|
|
@ -141,6 +141,49 @@ static int traceback (lua_State *L) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int finish_dfhack_safecall (lua_State *L, bool success)
|
|
|
|
|
{
|
|
|
|
|
if (!lua_checkstack(L, 1))
|
|
|
|
|
{
|
|
|
|
|
lua_settop(L, 0); /* create space for return values */
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
lua_pushstring(L, "stack overflow in dfhack.safecall()");
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lua_pushboolean(L, success);
|
|
|
|
|
lua_replace(L, 1); /* put first result in first slot */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
const char *msg = lua_tostring(L, -1);
|
|
|
|
|
if (!msg) msg = "In dfhack.safecall: error message is not a string.";
|
|
|
|
|
if (color_ostream *out = Lua::GetOutput(L))
|
|
|
|
|
out->printerr("%s\n", msg);
|
|
|
|
|
else
|
|
|
|
|
Core::printerr("%s\n", msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lua_gettop(L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int safecall_cont (lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
int status = lua_getctx(L, NULL);
|
|
|
|
|
return finish_dfhack_safecall(L, (status == LUA_YIELD));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_safecall (lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
luaL_checkany(L, 1);
|
|
|
|
|
lua_pushcfunction(L, traceback);
|
|
|
|
|
lua_insert(L, 1);
|
|
|
|
|
int status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 1, 0, safecall_cont);
|
|
|
|
|
return finish_dfhack_safecall(L, (status == LUA_OK));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void report_error(color_ostream &out, lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
const char *msg = lua_tostring(L, -1);
|
|
|
|
@ -189,24 +232,48 @@ bool DFHack::Lua::Require(color_ostream &out, lua_State *state,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool load_with_env(color_ostream &out, lua_State *state, const std::string &code, int eidx)
|
|
|
|
|
bool DFHack::Lua::AssignDFObject(color_ostream &out, lua_State *state,
|
|
|
|
|
type_identity *type, void *target, int val_index, bool perr)
|
|
|
|
|
{
|
|
|
|
|
if (luaL_loadbuffer(state, code.data(), code.size(), "=(interactive)") != LUA_OK)
|
|
|
|
|
val_index = lua_absindex(state, val_index);
|
|
|
|
|
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
|
|
|
|
|
PushDFObject(state, type, target);
|
|
|
|
|
lua_pushvalue(state, val_index);
|
|
|
|
|
return Lua::SafeCall(out, state, 2, 0, perr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DFHack::Lua::SafeCallString(color_ostream &out, lua_State *state, const std::string &code,
|
|
|
|
|
int nargs, int nres, bool perr,
|
|
|
|
|
const char *debug_tag, int env_idx)
|
|
|
|
|
{
|
|
|
|
|
if (!debug_tag)
|
|
|
|
|
debug_tag = code.c_str();
|
|
|
|
|
if (env_idx)
|
|
|
|
|
env_idx = lua_absindex(state, env_idx);
|
|
|
|
|
|
|
|
|
|
int base = lua_gettop(state);
|
|
|
|
|
|
|
|
|
|
// Parse the code
|
|
|
|
|
if (luaL_loadbuffer(state, code.data(), code.size(), debug_tag) != LUA_OK)
|
|
|
|
|
{
|
|
|
|
|
report_error(out, state);
|
|
|
|
|
if (perr)
|
|
|
|
|
report_error(out, state);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Replace _ENV
|
|
|
|
|
lua_pushvalue(state, eidx);
|
|
|
|
|
|
|
|
|
|
if (!lua_setupvalue(state, -2, 1))
|
|
|
|
|
if (env_idx)
|
|
|
|
|
{
|
|
|
|
|
out.printerr("No _ENV upvalue.\n");
|
|
|
|
|
return false;
|
|
|
|
|
lua_pushvalue(state, env_idx);
|
|
|
|
|
lua_setupvalue(state, -2, 1);
|
|
|
|
|
assert(lua_gettop(state) == base+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
if (nargs > 0)
|
|
|
|
|
lua_insert(state, -1-nargs);
|
|
|
|
|
|
|
|
|
|
return Lua::SafeCall(out, state, nargs, nres, perr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
@ -273,9 +340,7 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
{
|
|
|
|
|
curline = "return " + curline.substr(1);
|
|
|
|
|
|
|
|
|
|
if (!load_with_env(out, state, curline, base))
|
|
|
|
|
continue;
|
|
|
|
|
if (!SafeCall(out, state, 0, LUA_MULTRET))
|
|
|
|
|
if (!Lua::SafeCallString(out, state, curline, 0, LUA_MULTRET, true, "=(interactive)", base))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
int numret = lua_gettop(state) - base;
|
|
|
|
@ -309,9 +374,7 @@ bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!load_with_env(out, state, curline, base))
|
|
|
|
|
continue;
|
|
|
|
|
if (!SafeCall(out, state, 0, 0))
|
|
|
|
|
if (!Lua::SafeCallString(out, state, curline, 0, LUA_MULTRET, true, "=(interactive)", base))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -352,8 +415,7 @@ static int lua_dfhack_interpreter(lua_State *state)
|
|
|
|
|
|
|
|
|
|
static int lua_dfhack_with_suspend(lua_State *L)
|
|
|
|
|
{
|
|
|
|
|
int ctx;
|
|
|
|
|
int rv = lua_getctx(L, &ctx);
|
|
|
|
|
int rv = lua_getctx(L, NULL);
|
|
|
|
|
|
|
|
|
|
// Non-resume entry point:
|
|
|
|
|
if (rv == LUA_OK)
|
|
|
|
@ -385,7 +447,8 @@ static const luaL_Reg dfhack_funcs[] = {
|
|
|
|
|
{ "print", lua_dfhack_print },
|
|
|
|
|
{ "println", lua_dfhack_println },
|
|
|
|
|
{ "printerr", lua_dfhack_printerr },
|
|
|
|
|
{ "traceback", traceback },
|
|
|
|
|
{ "safecall", lua_dfhack_safecall },
|
|
|
|
|
{ "onerror", traceback },
|
|
|
|
|
{ "interpreter", lua_dfhack_interpreter },
|
|
|
|
|
{ "with_suspend", lua_dfhack_with_suspend },
|
|
|
|
|
{ NULL, NULL }
|
|
|
|
|