/* ** Global State ** See Copyright Notice in lua.h */ #define FORBIDDEN_SYMBOL_EXCEPTION_setjmp #define FORBIDDEN_SYMBOL_EXCEPTION_longjmp #define FORBIDDEN_SYMBOL_EXCEPTION_stdin #define FORBIDDEN_SYMBOL_EXCEPTION_stdout #define FORBIDDEN_SYMBOL_EXCEPTION_stderror #define FORBIDDEN_SYMBOL_EXCEPTION_fprintf #define FORBIDDEN_SYMBOL_EXCEPTION_FILE #include "common/endian.h" #include "engines/grim/debug.h" #include "engines/grim/actor.h" #include "engines/grim/color.h" #include "engines/grim/lua/lbuiltin.h" #include "engines/grim/lua/ldo.h" #include "engines/grim/lua/lauxlib.h" #include "engines/grim/lua/lfunc.h" #include "engines/grim/lua/lgc.h" #include "engines/grim/lua/llex.h" #include "engines/grim/lua/lmem.h" #include "engines/grim/lua/lstate.h" #include "engines/grim/lua/lstring.h" #include "engines/grim/lua/ltable.h" #include "engines/grim/lua/ltask.h" #include "engines/grim/lua/ltm.h" #include "engines/grim/lua/lualib.h" #include "engines/grim/lua/luadebug.h" namespace Grim { GCnode rootproto; GCnode rootcl; GCnode rootglobal; GCnode roottable; struct ref *refArray; int32 refSize; int32 GCthreshold; int32 nblocks; int32 Mbuffsize; int32 Mbuffnext; char *Mbuffbase; char *Mbuffer; TObject errorim; stringtable *string_root; int32 last_tag; struct IM *IMtable; int32 IMtable_size; LState *lua_state = nullptr; LState *lua_rootState = nullptr; int globalTaskSerialId = 0; void stderrorim(); static luaL_reg stdErrorRimFunc[] = { { "stderrorim", stderrorim } }; static void lua_openthr() { Mbuffsize = 0; Mbuffnext = 0; Mbuffbase = nullptr; Mbuffer = nullptr; } #define STACK_UNIT 256 void lua_stateinit(LState *state) { state->prev = nullptr; state->next = nullptr; state->all_paused = 0; state->paused = false; state->preventBreakCounter = 0; state->callLevelCounter = 0; state->updated = false; state->numCblocks = 0; state->Cstack.base = 0; state->Cstack.lua2C = 0; state->Cstack.num = 0; state->errorJmp = nullptr; state->id = globalTaskSerialId++; state->task = nullptr; state->prevTask = nullptr; state->taskFunc.ttype = LUA_T_NIL; state->sleepFor = 0; state->stack.stack = luaM_newvector(STACK_UNIT, TObject); state->stack.top = state->stack.stack; state->stack.last = state->stack.stack + (STACK_UNIT - 1); } void lua_statedeinit(LState *state) { if (state->prev) state->prev->next = state->next; if (state->next) state->next->prev = state->prev; state->next = nullptr; state->prev = nullptr; if (state->task) { lua_Task *t, *m; for (t = state->task; t != nullptr;) { m = t->next; luaM_free(t); t = m; } } free(state->stack.stack); } void lua_resetglobals() { lua_openthr(); rootproto.next = nullptr; rootproto.marked = 0; rootcl.next = nullptr; rootcl.marked = 0; rootglobal.next = nullptr; rootglobal.marked = 0; roottable.next = nullptr; roottable.marked = 0; refArray = nullptr; refSize = 0; GCthreshold = GARBAGE_BLOCK; nblocks = 0; luaD_init(); luaS_init(); luaX_init(); } void callHook(lua_Function func, const char *filename, int32 line) { const char *name, *type; FILE *output = stdout; int i; for (i = 0; i < lua_state->callLevelCounter; i++) { fprintf(output, " "); } fprintf(output, "id: %d ", lua_state->id); type = lua_getobjname(func, &name); if (func == LUA_NOOBJECT) { fprintf(output, "<< %s\n", filename); return; } else { fprintf(output, ">> %s ", filename); } switch (*type) { case 'g': fprintf(output, "function: %s(", name); for (i = 1; ; i++) { if (lua_getparam(i) == LUA_NOOBJECT) break; if (lua_isnil(lua_getparam(i))) fprintf(output, "nil"); else if (lua_istable(lua_getparam(i))) fprintf(output, "{...}"); else if (lua_isuserdata(lua_getparam(i))) { if (lua_tag(lua_getparam(i)) == MKTAG('A','C','T','R')) { Actor *a = Actor::getPool().getObject(lua_getuserdata(lua_getparam(i))); fprintf(output, "", a->getName().c_str()); } else if (lua_tag(lua_getparam(i)) == MKTAG('C','O','L','R')) { Color c(lua_getuserdata(lua_getparam(i))); fprintf(output, "", c.getRed(), c.getGreen(), c.getBlue()); } else fprintf(output, "", lua_getuserdata(lua_getparam(i))); } else if (lua_isfunction(lua_getparam(i))) { lua_getobjname(lua_getparam(i), &name); fprintf(output, "", name); } else if (lua_isnumber(lua_getparam(i))) fprintf(output, "%g", lua_getnumber(lua_getparam(i))); else if (lua_isstring(lua_getparam(i))) fprintf(output, "\"%s\"", lua_getstring(lua_getparam(i))); else fprintf(output, ""); if (lua_getparam(i + 1) != LUA_NOOBJECT) fprintf(output, ", "); } fprintf(output, ")"); break; case 't': fprintf(output, "`%s' tag method", name); break; default: { if (line == 0) fprintf(output, "{START SCRIPT: %s}", filename); else if (line < 0) { fprintf(output, "Unknown %s", filename); } else fprintf(output, "function (%s:%d)", filename, line); } } fprintf(output, "\n"); } void lua_open() { if (lua_state) return; lua_rootState = lua_state = luaM_new(LState); lua_stateinit(lua_state); lua_resetglobals(); luaT_init(); luaB_predefine(); luaL_addlibtolist(stdErrorRimFunc, (sizeof(stdErrorRimFunc) / sizeof(stdErrorRimFunc[0]))); if (Debug::isChannelEnabled(Debug::Lua)) lua_callhook = callHook; } void lua_close() { TaggedString *alludata = luaS_collectudata(); GCthreshold = MAX_INT; // to avoid GC during GC luaC_hashcallIM((Hash *)roottable.next); // GC t.methods for tables luaC_strcallIM(alludata); // GC tag methods for userdata luaD_gcIM(&luaO_nilobject); // GC tag method for nil (signal end of GC) luaH_free((Hash *)roottable.next); luaF_freeproto((TProtoFunc *)rootproto.next); luaF_freeclosure((Closure *)rootcl.next); luaS_free(alludata); luaS_freeall(); luaM_free(IMtable); luaM_free(refArray); luaM_free(Mbuffer); LState *tmpState, *state; for (state = lua_rootState; state != nullptr;) { tmpState = state->next; lua_statedeinit(state); luaM_free(state); state = tmpState; } Mbuffer = nullptr; IMtable = nullptr; refArray = nullptr; lua_rootState = lua_state = nullptr; #ifdef LUA_DEBUG printf("total de blocos: %ld\n", numblocks); printf("total de memoria: %ld\n", totalmem); #endif } bool lua_isopen() { return (lua_rootState); } } // end of namespace Grim