mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 05:32:45 +00:00
249 lines
6.2 KiB
C++
249 lines
6.2 KiB
C++
/*
|
|
** Tag methods
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
|
|
|
#include "engines/grim/lua/lauxlib.h"
|
|
#include "engines/grim/lua/lmem.h"
|
|
#include "engines/grim/lua/lobject.h"
|
|
#include "engines/grim/lua/lstate.h"
|
|
#include "engines/grim/lua/ltm.h"
|
|
#include "engines/grim/lua/lapi.h"
|
|
|
|
namespace Grim {
|
|
|
|
const char *luaT_eventname[] = { // ORDER IM
|
|
"gettable", "settable", "index", "getglobal", "setglobal", "add",
|
|
"sub", "mul", "div", "pow", "unm", "lt", "le", "gt", "ge",
|
|
"concat", "gc", "function", nullptr
|
|
};
|
|
|
|
static int32 luaI_checkevent(const char *name, const char *list[]) {
|
|
int32 e = luaO_findstring(name, list);
|
|
if (e < 0)
|
|
luaL_verror("`%.50s' is not a valid event name", name);
|
|
return e;
|
|
}
|
|
|
|
/* events in LUA_T_NIL are all allowed, since this is used as a
|
|
* 'placeholder' for "default" fallbacks
|
|
*/
|
|
static char validevents[NUM_TAGS][IM_N] = { // ORDER LUA_T, ORDER IM
|
|
{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, // LUA_T_USERDATA
|
|
{1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, // LUA_T_NUMBER
|
|
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, // LUA_T_STRING
|
|
{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // LUA_T_ARRAY
|
|
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, // LUA_T_PROTO
|
|
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, // LUA_T_CPROTO
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // LUA_T_TASK
|
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} // LUA_T_NIL
|
|
};
|
|
|
|
static int32 validevent(int32 t, int32 e) { // ORDER LUA_T
|
|
return (t < LUA_T_NIL) ? 1 : validevents[-t][e];
|
|
}
|
|
|
|
static void init_entry(int32 tag) {
|
|
for (int32 i = 0; i < IM_N; i++)
|
|
ttype(luaT_getim(tag, i)) = LUA_T_NIL;
|
|
}
|
|
|
|
static bool tmFBAdded = false;
|
|
|
|
void luaT_init() {
|
|
IMtable_size = NUM_TAGS * 2;
|
|
last_tag = -(NUM_TAGS - 1);
|
|
IMtable = luaM_newvector(IMtable_size, struct IM);
|
|
for (int32 t = -(IMtable_size - 1); t <= 0; t++)
|
|
init_entry(t);
|
|
|
|
tmFBAdded = false;
|
|
}
|
|
|
|
int32 lua_newtag() {
|
|
--last_tag;
|
|
if (-last_tag >= IMtable_size)
|
|
IMtable_size = luaM_growvector(&IMtable, IMtable_size, struct IM, memEM, MAX_INT);
|
|
init_entry(last_tag);
|
|
return last_tag;
|
|
}
|
|
|
|
static void checktag(int32 tag) {
|
|
if (!(last_tag <= tag && tag <= 0))
|
|
luaL_verror("%d is not a valid tag", tag);
|
|
}
|
|
|
|
void luaT_realtag(int32 tag) {
|
|
if (!(last_tag <= tag && tag < LUA_T_NIL))
|
|
luaL_verror("tag %d is not result of `newtag'", tag);
|
|
}
|
|
|
|
int32 lua_copytagmethods(int32 tagto, int32 tagfrom) {
|
|
int32 e;
|
|
checktag(tagto);
|
|
checktag(tagfrom);
|
|
for (e = 0; e < IM_N; e++) {
|
|
if (validevent(tagto, e))
|
|
*luaT_getim(tagto, e) = *luaT_getim(tagfrom, e);
|
|
}
|
|
return tagto;
|
|
}
|
|
|
|
int32 luaT_efectivetag(TObject *o) {
|
|
int32 t;
|
|
switch (t = ttype(o)) {
|
|
case LUA_T_ARRAY:
|
|
return o->value.a->htag;
|
|
case LUA_T_USERDATA:
|
|
{
|
|
int32 tag = o->value.ud.tag;
|
|
return (tag >= 0) ? LUA_T_USERDATA : tag;
|
|
}
|
|
case LUA_T_CLOSURE:
|
|
return o->value.cl->consts[0].ttype;
|
|
#ifdef LUA_DEBUG
|
|
case LUA_T_PMARK:
|
|
case LUA_T_CMARK:
|
|
case LUA_T_CLMARK:
|
|
case LUA_T_LINE:
|
|
lua_error("internal error");
|
|
#endif
|
|
default:
|
|
return t;
|
|
}
|
|
}
|
|
|
|
TObject *luaT_gettagmethod(int32 t, const char *event) {
|
|
int32 e = luaI_checkevent(event, luaT_eventname);
|
|
checktag(t);
|
|
if (validevent(t, e))
|
|
return luaT_getim(t,e);
|
|
else
|
|
return &luaO_nilobject;
|
|
}
|
|
|
|
void luaT_settagmethod(int32 t, const char *event, TObject *func) {
|
|
TObject temp = *func;
|
|
int32 e = luaI_checkevent(event, luaT_eventname);
|
|
checktag(t);
|
|
if (!validevent(t, e))
|
|
luaL_verror("settagmethod: cannot change tag method `%.20s' for tag %d",
|
|
luaT_eventname[e], t);
|
|
*func = *luaT_getim(t,e);
|
|
*luaT_getim(t, e) = temp;
|
|
}
|
|
|
|
const char *luaT_travtagmethods(int32 (*fn)(TObject *)) {
|
|
int32 e;
|
|
if (fn(&errorim))
|
|
return "error";
|
|
for (e = IM_GETTABLE; e <= IM_FUNCTION; e++) { // ORDER IM
|
|
int32 t;
|
|
for (t = 0; t >= last_tag; t--)
|
|
if (fn(luaT_getim(t, e)))
|
|
return luaT_eventname[e];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/*
|
|
* compatibility with old fallback system
|
|
*/
|
|
#ifdef LUA_COMPAT2_5
|
|
|
|
void errorFB() {
|
|
lua_Object o = lua_getparam(1);
|
|
if (lua_isstring(o))
|
|
fprintf(stderr, "lua: %s\n", lua_getstring(o));
|
|
else
|
|
fprintf(stderr, "lua: unknown error\n");
|
|
}
|
|
|
|
void nilFB() { }
|
|
|
|
void typeFB () {
|
|
lua_error("unexpected type");
|
|
}
|
|
|
|
static void fillvalids(IMS e, TObject *func) {
|
|
int32 t;
|
|
for (t = LUA_T_NIL; t <= LUA_T_USERDATA; t++)
|
|
if (validevent(t, e))
|
|
*luaT_getim(t, e) = *func;
|
|
}
|
|
|
|
static luaL_reg tmFB[] = {
|
|
{" typeFB", typeFB},
|
|
{" errorFB", errorFB},
|
|
{" nilFB", nilFB}
|
|
};
|
|
|
|
void luaT_setfallback() {
|
|
static const char *oldnames [] = { "error", "getglobal", "arith", "order", nullptr };
|
|
TObject oldfunc;
|
|
lua_CFunction replace;
|
|
if (!tmFBAdded) {
|
|
luaL_addlibtolist(tmFB, (sizeof(tmFB) / sizeof(tmFB[0])));
|
|
tmFBAdded = true;
|
|
}
|
|
const char *name = luaL_check_string(1);
|
|
lua_Object func = lua_getparam(2);
|
|
luaL_arg_check(lua_isfunction(func), 2, "function expected");
|
|
switch (luaO_findstring(name, oldnames)) {
|
|
case 0: // old error fallback
|
|
oldfunc = errorim;
|
|
errorim = *luaA_Address(func);
|
|
replace = errorFB;
|
|
break;
|
|
case 1: // old getglobal fallback
|
|
oldfunc = *luaT_getim(LUA_T_NIL, IM_GETGLOBAL);
|
|
*luaT_getim(LUA_T_NIL, IM_GETGLOBAL) = *luaA_Address(func);
|
|
replace = nilFB;
|
|
break;
|
|
case 2:
|
|
{ // old arith fallback
|
|
int32 i;
|
|
oldfunc = *luaT_getim(LUA_T_NUMBER, IM_POW);
|
|
for (i = IM_ADD; i <= IM_UNM; i++) // ORDER IM
|
|
fillvalids(i, luaA_Address(func));
|
|
replace = typeFB;
|
|
break;
|
|
}
|
|
case 3:
|
|
{ // old order fallback
|
|
int32 i;
|
|
oldfunc = *luaT_getim(LUA_T_NIL, IM_LT);
|
|
for (i = IM_LT; i <= IM_GE; i++) // ORDER IM
|
|
fillvalids(i, luaA_Address(func));
|
|
replace = typeFB;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
int32 e;
|
|
if ((e = luaO_findstring(name, luaT_eventname)) >= 0) {
|
|
oldfunc = *luaT_getim(LUA_T_NIL, e);
|
|
fillvalids(e, luaA_Address(func));
|
|
replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB;
|
|
} else {
|
|
luaL_verror("`%.50s' is not a valid fallback name", name);
|
|
replace = nullptr; // to avoid warnings
|
|
oldfunc.ttype = LUA_T_NIL; // to avoid warnings
|
|
}
|
|
}
|
|
}
|
|
if (oldfunc.ttype != LUA_T_NIL)
|
|
luaA_pushobject(&oldfunc);
|
|
else
|
|
lua_pushcfunction(replace);
|
|
}
|
|
|
|
#endif
|
|
|
|
} // end of namespace Grim
|