Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
This is a modified version of Lua 3.1 intended for use with ResidualVM.
The major changes made from the original version of Lua 3.1 are:
* Applied differences from RCS labeled 3.1-alpha from lua.org.
* Changed the binary file loader to allow read GrimE lua files.
* Revamped the way function calls and returns are handled in order to
facilitate implementing GrimE's cooperative multithreading model.
* Added several internal functions which implement this multithreading.
* Added save/restore Lua state in the files: lsave.cpp and lrestore.cpp.
* Unified types like int -> int32 and similiars.
* Removed few library functions not used by game engine.
* Formatting code.
* Replace FILE usage code with File class code.
* Remove union from TaggedString, that simplify things.

505
engines/grim/lua/lapi.cpp Normal file
View File

@@ -0,0 +1,505 @@
/*
** Lua API
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/lapi.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lgc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/ltable.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/luadebug.h"
#include "engines/grim/lua/lvm.h"
namespace Grim {
char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n"
"$Autores: " LUA_AUTHORS " $";
TObject *luaA_Address(lua_Object o) {
return Address(o);
}
static int32 normalized_type(TObject *o) {
int32 t = ttype(o);
switch (t) {
case LUA_T_PMARK:
return LUA_T_PROTO;
case LUA_T_CMARK:
return LUA_T_CPROTO;
case LUA_T_CLMARK:
return LUA_T_CLOSURE;
default:
return t;
}
}
void set_normalized(TObject *d, TObject *s) {
d->value = s->value;
d->ttype = (lua_Type)normalized_type(s);
}
static TObject *luaA_protovalue (TObject *o) {
return (normalized_type(o) == LUA_T_CLOSURE) ? protovalue(o) : o;
}
void luaA_packresults() {
luaV_pack(lua_state->Cstack.lua2C, lua_state->Cstack.num, lua_state->stack.top);
incr_top;
}
int32 luaA_passresults() {
luaD_checkstack(lua_state->Cstack.num);
memcpy(lua_state->stack.top, lua_state->Cstack.lua2C + lua_state->stack.stack, lua_state->Cstack.num * sizeof(TObject));
lua_state->stack.top += lua_state->Cstack.num;
return lua_state->Cstack.num;
}
static void checkCparams(int32 nParams) {
if (lua_state->stack.top - lua_state->stack.stack < lua_state->Cstack.base + nParams)
lua_error("API error - wrong number of arguments in C2lua stack");
}
static lua_Object put_luaObject(TObject *o) {
luaD_openstack((lua_state->stack.top - lua_state->stack.stack) - lua_state->Cstack.base);
lua_state->stack.stack[lua_state->Cstack.base++] = *o;
return lua_state->Cstack.base; // this is +1 real position (see Ref)
}
static lua_Object put_luaObjectonTop() {
luaD_openstack((lua_state->stack.top - lua_state->stack.stack) - lua_state->Cstack.base);
lua_state->stack.stack[lua_state->Cstack.base++] = *(--lua_state->stack.top);
return lua_state->Cstack.base; // this is +1 real position (see Ref)
}
lua_Object lua_pop() {
checkCparams(1);
return put_luaObjectonTop();
}
/*
** Get a parameter, returning the object handle or LUA_NOOBJECT on error.
** 'number' must be 1 to get the first parameter.
*/
lua_Object lua_lua2C(int32 number) {
if (number <= 0 || number > lua_state->Cstack.num)
return LUA_NOOBJECT;
return lua_state->Cstack.lua2C + number;
}
int32 lua_callfunction(lua_Object function) {
if (function == LUA_NOOBJECT) {
return 1;
} else {
luaD_openstack((lua_state->stack.top - lua_state->stack.stack) - lua_state->Cstack.base);
set_normalized(lua_state->stack.stack + lua_state->Cstack.base, Address(function));
return luaD_protectedrun(MULT_RET);
}
}
lua_Object lua_gettagmethod(int32 tag, const char *event) {
return put_luaObject(luaT_gettagmethod(tag, event));
}
lua_Object lua_settagmethod(int32 tag, const char *event) {
checkCparams(1);
luaT_settagmethod(tag, event, lua_state->stack.top - 1);
return put_luaObjectonTop();
}
lua_Object lua_seterrormethod() {
TObject temp = errorim;
checkCparams(1);
errorim = *(--lua_state->stack.top);
return put_luaObject(&temp);
}
lua_Object lua_gettable() {
checkCparams(2);
luaV_gettable();
return put_luaObjectonTop();
}
lua_Object lua_rawgettable() {
checkCparams(2);
if (ttype(lua_state->stack.top-2) != LUA_T_ARRAY) {
lua_error("indexed expression not a table in rawgettable");
} else {
TObject *h = luaH_get(avalue(lua_state->stack.top - 2), lua_state->stack.top - 1);
--lua_state->stack.top;
if (h) {
*(lua_state->stack.top-1) = *h;
} else {
ttype(lua_state->stack.top-1) = LUA_T_NIL;
}
}
return put_luaObjectonTop();
}
void lua_settable() {
checkCparams(3);
luaV_settable(lua_state->stack.top-3, 1);
}
void lua_rawsettable() {
checkCparams(3);
luaV_settable(lua_state->stack.top-3, 0);
}
lua_Object lua_createtable() {
TObject o;
luaC_checkGC();
avalue(&o) = luaH_new(0);
ttype(&o) = LUA_T_ARRAY;
return put_luaObject(&o);
}
lua_Object lua_getglobal(const char *name) {
luaD_checkstack(2); // may need that to call T.M.
luaV_getglobal(luaS_new(name));
return put_luaObjectonTop();
}
lua_Object lua_rawgetglobal(const char *name) {
TaggedString *ts = luaS_new(name);
return put_luaObject(&ts->globalval);
}
void lua_setglobal(const char *name) {
checkCparams(1);
luaD_checkstack(2); // may need that to call T.M.
luaV_setglobal(luaS_new(name));
}
void lua_rawsetglobal(const char *name) {
TaggedString *ts = luaS_new(name);
checkCparams(1);
luaS_rawsetglobal(ts, --lua_state->stack.top);
}
int32 lua_isnil(lua_Object o) {
return (o == LUA_NOOBJECT) || (ttype(Address(o)) == LUA_T_NIL);
}
int32 lua_istable(lua_Object o) {
return (o != LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_ARRAY);
}
int32 lua_isuserdata(lua_Object o) {
return (o != LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_USERDATA);
}
int32 lua_iscfunction(lua_Object o) {
return (lua_tag(o) == LUA_T_CPROTO);
}
int32 lua_isnumber(lua_Object o) {
return (o!= LUA_NOOBJECT) && (tonumber(Address(o)) == 0);
}
int32 lua_isstring(lua_Object o) {
int32 t = lua_tag(o);
return (t == LUA_T_STRING) || (t == LUA_T_NUMBER);
}
int32 lua_isfunction(lua_Object o) {
int32 t = lua_tag(o);
return (t == LUA_T_PROTO) || (t == LUA_T_CPROTO);
}
float lua_getnumber(lua_Object object) {
if (object == LUA_NOOBJECT)
return 0.0f;
if (tonumber(Address(object)))
return 0.0f;
else
return (nvalue(Address(object)));
}
const char *lua_getstring (lua_Object object) {
if (object == LUA_NOOBJECT || tostring(Address(object)))
return nullptr;
else
return (svalue(Address(object)));
}
int32 lua_getuserdata(lua_Object object) {
if (object == LUA_NOOBJECT || ttype(Address(object)) != LUA_T_USERDATA)
return 0;
else
return (Address(object))->value.ud.id;
}
lua_CFunction lua_getcfunction(lua_Object object) {
if (!lua_iscfunction(object))
return nullptr;
else
return fvalue(luaA_protovalue(Address(object)));
}
void lua_pushnil() {
ttype(lua_state->stack.top) = LUA_T_NIL;
incr_top;
}
void lua_pushnumber(float n) {
ttype(lua_state->stack.top) = LUA_T_NUMBER;
nvalue(lua_state->stack.top) = n;
incr_top;
}
void lua_pushstring(const char *s) {
if (!s)
ttype(lua_state->stack.top) = LUA_T_NIL;
else {
tsvalue(lua_state->stack.top) = luaS_new(s);
ttype(lua_state->stack.top) = LUA_T_STRING;
}
incr_top;
luaC_checkGC();
}
void lua_pushCclosure(lua_CFunction fn, int32 n) {
if (!fn)
lua_error("API error - attempt to push a NULL Cfunction");
checkCparams(n);
ttype(lua_state->stack.top) = LUA_T_CPROTO;
fvalue(lua_state->stack.top) = fn;
incr_top;
luaV_closure(n);
}
void lua_pushusertag(int32 u, int32 tag) {
if (tag < 0 && tag != LUA_ANYTAG)
luaT_realtag(tag); // error if tag is not valid
lua_state->stack.top->value.ud.id = u;
lua_state->stack.top->value.ud.tag = tag;
ttype(lua_state->stack.top) = LUA_T_USERDATA;
incr_top;
luaC_checkGC();
}
void luaA_pushobject(TObject *o) {
*lua_state->stack.top = *o;
incr_top;
}
void lua_pushobject(lua_Object o) {
if (o == LUA_NOOBJECT)
lua_error("API error - attempt to push a NOOBJECT");
else {
set_normalized(lua_state->stack.top, Address(o));
incr_top;
}
}
int32 lua_tag(lua_Object lo) {
if (lo == LUA_NOOBJECT)
return LUA_T_NIL;
else {
TObject *o = Address(lo);
int32 t;
switch (t = ttype(o)) {
case LUA_T_USERDATA:
return o->value.ud.tag;
case LUA_T_ARRAY:
return o->value.a->htag;
case LUA_T_PMARK:
return LUA_T_PROTO;
case LUA_T_CMARK:
return LUA_T_CPROTO;
case LUA_T_CLOSURE:
// fall through
case LUA_T_CLMARK:
return o->value.cl->consts[0].ttype;
#ifdef LUA_DEBUG
case LUA_T_LINE:
LUA_INTERNALERROR("internal error");
#endif
default:
return t;
}
}
}
void lua_settag(int32 tag) {
checkCparams(1);
luaT_realtag(tag);
switch (ttype(lua_state->stack.top - 1)) {
case LUA_T_ARRAY:
(lua_state->stack.top - 1)->value.a->htag = tag;
break;
case LUA_T_USERDATA:
(lua_state->stack.top - 1)->value.ud.tag = tag;
break;
default:
luaL_verror("cannot change the tag of a %.20s", luaO_typenames[-ttype((lua_state->stack.top - 1))]);
}
lua_state->stack.top--;
}
/*
** =======================================================
** Debug interface
** =======================================================
*/
// Hooks
lua_CHFunction lua_callhook = nullptr;
lua_LHFunction lua_linehook = nullptr;
lua_Function lua_stackedfunction(int32 level) {
StkId i;
for (i = (lua_state->stack.top - 1) - lua_state->stack.stack; i >= 0; i--) {
int32 t = lua_state->stack.stack[i].ttype;
if (t == LUA_T_CLMARK || t == LUA_T_PMARK || t == LUA_T_CMARK)
if (level-- == 0)
return Ref(lua_state->stack.stack + i);
}
return LUA_NOOBJECT;
}
int32 lua_currentline(lua_Function func) {
TObject *f = Address(func);
return (f + 1 < lua_state->stack.top && (f + 1)->ttype == LUA_T_LINE) ? (f + 1)->value.i : -1;
}
lua_Object lua_getlocal(lua_Function func, int32 local_number, char **name) {
// check whether func is a Lua function
if (lua_tag(func) != LUA_T_PROTO)
return LUA_NOOBJECT;
else {
TObject *f = Address(func);
TProtoFunc *fp = luaA_protovalue(f)->value.tf;
*name = luaF_getlocalname(fp, local_number, lua_currentline(func));
if (*name) {
// if "*name", there must be a LUA_T_LINE
// therefore, f + 2 points to function base
return Ref((f + 2) + (local_number - 1));
} else
return LUA_NOOBJECT;
}
}
int32 lua_setlocal(lua_Function func, int32 local_number) {
// check whether func is a Lua function
if (lua_tag(func) != LUA_T_PROTO)
return 0;
else {
TObject *f = Address(func);
TProtoFunc *fp = luaA_protovalue(f)->value.tf;
char *name = luaF_getlocalname(fp, local_number, lua_currentline(func));
checkCparams(1);
--lua_state->stack.top;
if (name) {
// if "name", there must be a LUA_T_LINE
// therefore, f+2 points to function base
*((f + 2) + (local_number - 1)) = *lua_state->stack.top;
return 1;
} else
return 0;
}
}
void lua_funcinfo(lua_Object func, const char **filename, int32 *linedefined) {
if (!lua_isfunction(func))
lua_error("API - `funcinfo' called with a non-function value");
else {
TObject *f = luaA_protovalue(Address(func));
if (normalized_type(f) == LUA_T_PROTO) {
*filename = tfvalue(f)->fileName->str;
*linedefined = tfvalue(f)->lineDefined;
} else {
*filename = "(C)";
*linedefined = -1;
}
}
}
static int32 checkfunc (TObject *o) {
return luaO_equalObj(o, lua_state->stack.top);
}
const char *lua_getobjname (lua_Object o, const char **name) {
// try to find a name for given function
set_normalized(lua_state->stack.top, Address(o)); // to be accessed by "checkfunc"
*name = luaT_travtagmethods(checkfunc);
if (*name)
return "tag-method";
*name = luaS_travsymbol(checkfunc);
if (*name)
return "global";
else
return "";
}
/*
** =======================================================
** BLOCK mechanism
** =======================================================
*/
void lua_beginblock() {
if (lua_state->numCblocks >= MAX_C_BLOCKS)
lua_error("too many nested blocks");
lua_state->Cblocks[lua_state->numCblocks] = lua_state->Cstack;
lua_state->numCblocks++;
}
void lua_endblock() {
--lua_state->numCblocks;
lua_state->Cstack = lua_state->Cblocks[lua_state->numCblocks];
luaD_adjusttop(lua_state->Cstack.base);
}
int32 lua_ref(int32 lock) {
int32 ref;
checkCparams(1);
ref = luaC_ref(lua_state->stack.top - 1, lock);
lua_state->stack.top--;
return ref;
}
lua_Object lua_getref(int32 r) {
TObject *o = luaC_getref(r);
return (o ? put_luaObject(o) : LUA_NOOBJECT);
}
#ifdef LUA_COMPAT2_5
/*
** API: set a function as a fallback
*/
static void do_unprotectedrun(lua_CFunction f, int32 nParams, int32 nResults) {
StkId base = (lua_state->stack.top - lua_state->stack.stack) - nParams;
luaD_openstack(nParams);
lua_state->stack.stack[base].ttype = LUA_T_CPROTO;
lua_state->stack.stack[base].value.f = f;
lua_state->preventBreakCounter++;
luaD_call(base + 1, nResults);
lua_state->preventBreakCounter--;
}
lua_Object lua_setfallback(const char *name, lua_CFunction fallback) {
lua_pushstring(name);
lua_pushcfunction(fallback);
do_unprotectedrun(luaT_setfallback, 2, 1);
return put_luaObjectonTop();
}
#endif
} // end of namespace Grim

23
engines/grim/lua/lapi.h Normal file
View File

@@ -0,0 +1,23 @@
/*
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LAPI_H
#define GRIM_LAPI_H
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/lobject.h"
namespace Grim {
TObject *luaA_Address(lua_Object o);
void luaA_pushobject(TObject *o);
void luaA_packresults();
int32 luaA_passresults();
void set_normalized(TObject *d, TObject *s);
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,107 @@
/*
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
/* Please Notice: This file uses only the official API of Lua
** Any function declared here could be written as an application
** function. With care, these functions can be used by other libraries.
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_vsprintf
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/luadebug.h"
#include "engines/grim/lua/lmem.h"
namespace Grim {
void luaL_argerror(int32 numarg, const char *extramsg) {
const char *funcname;
lua_getobjname(lua_stackedfunction(0), &funcname);
if (!funcname)
funcname = "???";
if (!extramsg)
luaL_verror("bad argument #%d to function `%.50s'", numarg, funcname);
else
luaL_verror("bad argument #%d to function `%.50s' (%.100s)", numarg, funcname, extramsg);
}
const char *luaL_check_string(int32 numArg) {
lua_Object o = lua_getparam(numArg);
luaL_arg_check(lua_isstring(o), numArg, "string expected");
return lua_getstring(o);
}
const char *luaL_opt_string(int32 numArg, const char *def) {
return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : luaL_check_string(numArg);
}
float luaL_check_number(int32 numArg) {
lua_Object o = lua_getparam(numArg);
luaL_arg_check(lua_isnumber(o), numArg, "number expected");
return lua_getnumber(o);
}
float luaL_opt_number(int32 numArg, float def) {
return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : luaL_check_number(numArg);
}
lua_Object luaL_tablearg(int32 arg) {
lua_Object o = lua_getparam(arg);
luaL_arg_check(lua_istable(o), arg, "table expected");
return o;
}
lua_Object luaL_functionarg(int32 arg) {
lua_Object o = lua_getparam(arg);
luaL_arg_check(lua_isfunction(o), arg, "function expected");
return o;
}
lua_Object luaL_nonnullarg(int32 numArg) {
lua_Object o = lua_getparam(numArg);
luaL_arg_check(o != LUA_NOOBJECT, numArg, "value expected");
return o;
}
luaL_libList *list_of_libs = nullptr;
void luaL_addlibtolist(luaL_reg *l, int32 n) {
luaL_libList *list = (luaL_libList *)luaM_malloc(sizeof(luaL_libList));
list->list = l;
list->number = n;
list->next = list_of_libs;
list_of_libs = list;
}
void lua_removelibslists() {
luaL_libList *list = list_of_libs;
while (list) {
luaL_libList *nextList = list->next;
luaM_free(list);
list = nextList;
}
list_of_libs = nullptr;
}
void luaL_openlib(luaL_reg *l, int32 n) {
int32 i;
lua_open(); // make sure lua is already open
for (i = 0; i < n; i++)
lua_register(l[i].name, l[i].func);
luaL_addlibtolist(l, n);
}
void luaL_verror(const char *fmt, ...) {
char buff[500];
va_list argp;
va_start(argp, fmt);
vsnprintf(buff, 100, fmt, argp);
va_end(argp);
lua_error(buff);
}
} // end of namespace Grim

View File

@@ -0,0 +1,51 @@
/*
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef GRIM_AUXLIB_H
#define GRIM_AUXLIB_H
#include "engines/grim/lua/lua.h"
namespace Grim {
struct luaL_reg {
const char *name;
lua_CFunction func;
};
struct luaL_libList {
luaL_reg *list;
int32 number;
luaL_libList *next;
};
extern luaL_libList *list_of_libs;
#define luaL_arg_check(cond, numarg, extramsg) if (!(cond)) luaL_argerror(numarg,extramsg)
void luaL_openlib(luaL_reg *l, int32 n);
void luaL_addlibtolist(luaL_reg *l, int32 n);
void luaL_argerror(int32 numarg, const char *extramsg);
const char *luaL_check_string(int32 numArg);
const char *luaL_opt_string(int32 numArg, const char *def);
float luaL_check_number(int32 numArg);
float luaL_opt_number(int32 numArg, float def);
lua_Object luaL_functionarg(int32 arg);
lua_Object luaL_tablearg(int32 arg);
lua_Object luaL_nonnullarg(int32 numArg);
void luaL_verror(const char *fmt, ...);
char *luaL_openspace(int32 size);
void luaL_resetbuffer();
void luaL_addchar(int32 c);
void luaL_addsize(int32 n);
int32 luaL_newbuffer(int32 size);
void luaL_oldbuffer(int32 old);
char *luaL_buffer();
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,66 @@
/*
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lstate.h"
namespace Grim {
/*-------------------------------------------------------
** Auxiliary buffer
-------------------------------------------------------*/
#define BUFF_STEP 32
#define openspace(size) if (Mbuffnext + (size) > Mbuffsize) Openspace(size)
static void Openspace(int32 size) {
int32 base = Mbuffbase - Mbuffer;
Mbuffsize *= 2;
if (Mbuffnext + size > Mbuffsize) // still not big enough?
Mbuffsize = Mbuffnext + size;
Mbuffer = (char *)luaM_realloc(Mbuffer, Mbuffsize);
Mbuffbase = Mbuffer + base;
}
char *luaL_openspace(int32 size) {
openspace(size);
return Mbuffer + Mbuffnext;
}
void luaL_addchar(int32 c) {
openspace(BUFF_STEP);
Mbuffer[Mbuffnext++] = c;
}
void luaL_resetbuffer() {
Mbuffnext = Mbuffbase - Mbuffer;
}
void luaL_addsize(int32 n) {
Mbuffnext += n;
}
int32 luaL_newbuffer(int32 size) {
int32 old = Mbuffbase - Mbuffer;
openspace(size);
Mbuffbase = Mbuffer + Mbuffnext;
return old;
}
void luaL_oldbuffer(int32 old) {
Mbuffnext = Mbuffbase - Mbuffer;
Mbuffbase = Mbuffer + old;
}
char *luaL_buffer() {
return Mbuffbase;
}
} // end of namespace Grim

View File

@@ -0,0 +1,531 @@
/*
** Built-in functions
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
#define FORBIDDEN_SYMBOL_EXCEPTION_sprintf
#include "common/util.h"
#include "engines/grim/lua/lapi.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lbuiltin.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lobject.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/lua.h"
namespace Grim {
static void pushstring(TaggedString *s) {
TObject o;
o.ttype = LUA_T_STRING;
o.value.ts = s;
luaA_pushobject(&o);
}
static void nextvar() {
TObject *o = luaA_Address(luaL_nonnullarg(1));
TaggedString *g;
if (ttype(o) == LUA_T_NIL)
g = (TaggedString *)rootglobal.next;
else {
luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected");
g = tsvalue(o);
// check whether name is in global var list
luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected");
g = (TaggedString *)g->head.next;
}
while (g && g->globalval.ttype == LUA_T_NIL) {
// skip globals with nil
g = (TaggedString *)g->head.next;
}
if (g) {
pushstring(g);
luaA_pushobject(&g->globalval);
}
}
static void foreachvar() {
TObject f = *luaA_Address(luaL_functionarg(1));
StkId name = lua_state->Cstack.base++; // place to keep var name (to avoid GC)
ttype(lua_state->stack.stack + name) = LUA_T_NIL;
lua_state->stack.top++;
for (GCnode *g = rootglobal.next; g; g = g->next) {
TaggedString *s = (TaggedString *)g;
if (s->globalval.ttype != LUA_T_NIL) {
ttype(lua_state->stack.stack + name) = LUA_T_STRING;
tsvalue(lua_state->stack.stack + name) = s; // keep s on stack to avoid GC
luaA_pushobject(&f);
pushstring(s);
luaA_pushobject(&s->globalval);
lua_state->preventBreakCounter++;
luaD_call((lua_state->stack.top - lua_state->stack.stack) - 2, 1);
lua_state->preventBreakCounter--;
if (ttype(lua_state->stack.top - 1) != LUA_T_NIL)
return;
lua_state->stack.top--;
}
}
}
static void next() {
lua_Object o = luaL_tablearg(1);
lua_Object r = luaL_nonnullarg(2);
Node *n = luaH_next(luaA_Address(o), luaA_Address(r));
if (n) {
luaA_pushobject(&n->ref);
luaA_pushobject(&n->val);
}
}
static void foreach() {
TObject t = *luaA_Address(luaL_tablearg(1));
TObject f = *luaA_Address(luaL_functionarg(2));
for (int32 i = 0; i < avalue(&t)->nhash; i++) {
Node *nd = &(avalue(&t)->node[i]);
if (ttype(ref(nd)) != LUA_T_NIL && ttype(val(nd)) != LUA_T_NIL) {
luaA_pushobject(&f);
luaA_pushobject(ref(nd));
luaA_pushobject(val(nd));
lua_state->preventBreakCounter++;
luaD_call((lua_state->stack.top - lua_state->stack.stack) - 2, 1);
lua_state->preventBreakCounter--;
if (ttype(lua_state->stack.top - 1) != LUA_T_NIL)
return;
lua_state->stack.top--;
}
}
}
static void internaldostring() {
if (lua_getparam(2) != LUA_NOOBJECT)
lua_error("invalid 2nd argument (probably obsolete code)");
if (lua_dostring(luaL_check_string(1)) == 0)
if (luaA_passresults() == 0)
lua_pushuserdata(0); // at least one result to signal no errors
}
static const char *to_string(lua_Object obj) {
char *buff = luaL_openspace(30);
TObject *o = luaA_Address(obj);
switch (ttype(o)) {
case LUA_T_NUMBER:
case LUA_T_STRING:
return lua_getstring(obj);
case LUA_T_ARRAY:
{
snprintf(buff, 30, "table: %p", (void *)o->value.a);
return buff;
}
case LUA_T_CLOSURE:
{
snprintf(buff, 30, "function: %p", (void *)o->value.cl);
return buff;
}
case LUA_T_PROTO:
{
snprintf(buff, 30, "function: %p", (void *)o->value.tf);
return buff;
}
case LUA_T_CPROTO:
{
// WORKAROUND: C++ forbids casting from a pointer-to-function to a
// pointer-to-object. We use a union to work around that.
union {
void *objPtr;
lua_CFunction funcPtr;
} ptrUnion;
ptrUnion.funcPtr = o->value.f;
snprintf(buff, 30, "function: %p", ptrUnion.objPtr);
return buff;
}
case LUA_T_USERDATA:
{
snprintf(buff, 30, "userdata: %08X", o->value.ud.id);
return buff;
}
case LUA_T_TASK:
{
snprintf(buff, 30, "task: %d", (int)o->value.n);
return buff;
}
case LUA_T_NIL:
return "nil";
default:
#ifdef LUA_DEBUG
LUA_INTERNALERROR("internal error");
#endif
return nullptr;
}
}
static void bi_tostring() {
lua_pushstring(to_string(lua_getparam(1)));
}
static void luaI_print() {
int32 i = 1;
lua_Object obj;
while ((obj = lua_getparam(i++)) != LUA_NOOBJECT)
printf("%s\t", to_string(obj));
printf("\n");
}
static void luaI_type() {
lua_Object o = luaL_nonnullarg(1);
lua_pushstring(luaO_typenames[-ttype(luaA_Address(o))]);
lua_pushnumber(lua_tag(o));
}
static void tonumber() {
int32 base = (int32)luaL_opt_number(2, 10);
if (base == 10) { // standard conversion
lua_Object o = lua_getparam(1);
if (lua_isnumber(o))
lua_pushnumber(lua_getnumber(o));
} else {
const char *s = luaL_check_string(1);
char *e;
luaL_arg_check(0 <= base && base <= 36, 2, "base out of range");
int32 n = (int32)strtol(s, &e, base);
while (Common::isSpace(*e))
e++; // skip trailing spaces
if (*e)
return; // invalid format: return nil
lua_pushnumber(n);
}
}
static void luaI_error() {
lua_error(lua_getstring(lua_getparam(1)));
}
static void luaI_assert() {
lua_Object p = lua_getparam(1);
if (p == LUA_NOOBJECT || lua_isnil(p))
luaL_verror("assertion failed! %.100s", luaL_opt_string(2, ""));
}
static void setglobal() {
const char *n = luaL_check_string(1);
lua_Object value = luaL_nonnullarg(2);
lua_pushobject(value);
lua_setglobal(n);
lua_pushobject(value); // return given value
}
static void rawsetglobal() {
const char *n = luaL_check_string(1);
lua_Object value = luaL_nonnullarg(2);
lua_pushobject(value);
lua_rawsetglobal(n);
lua_pushobject(value); // return given value
}
static void getglobal() {
lua_pushobject(lua_getglobal(luaL_check_string(1)));
}
static void rawgetglobal() {
lua_pushobject(lua_rawgetglobal(luaL_check_string(1)));
}
static void luatag() {
lua_pushnumber(lua_tag(lua_getparam(1)));
}
static int32 getnarg(lua_Object table) {
lua_Object temp;
// temp = table.n
lua_pushobject(table);
lua_pushstring("n");
temp = lua_rawgettable();
return (lua_isnumber(temp) ? (int32)lua_getnumber(temp) : MAX_WORD);
}
static void luaI_call() {
lua_Object f = luaL_nonnullarg(1);
lua_Object arg = luaL_tablearg(2);
const char *options = luaL_opt_string(3, "");
lua_Object err = lua_getparam(4);
int32 narg = getnarg(arg);
int32 i, status;
if (err != LUA_NOOBJECT) { // set new error method
lua_pushobject(err);
err = lua_seterrormethod();
}
// push arg[1...n]
for (i = 0; i < narg; i++) {
lua_Object temp;
// temp = arg[i + 1]
lua_pushobject(arg);
lua_pushnumber(i + 1);
temp = lua_rawgettable();
if (narg == MAX_WORD && lua_isnil(temp))
break;
lua_pushobject(temp);
}
status = lua_callfunction(f);
if (err != LUA_NOOBJECT) { // restore old error method
lua_pushobject(err);
lua_seterrormethod();
}
if (status) { // error in call?
if (strchr(options, 'x'))
return; // return nil to signal the error
else
lua_error(nullptr);
} else { // no errors
if (strchr(options, 'p'))
luaA_packresults();
else
luaA_passresults();
}
}
static void settag() {
lua_Object o = luaL_tablearg(1);
lua_pushobject(o);
lua_settag((int32)luaL_check_number(2));
}
static void newtag() {
lua_pushnumber(lua_newtag());
}
static void copytagmethods() {
lua_pushnumber(lua_copytagmethods((int32)luaL_check_number(1), (int32)luaL_check_number(2)));
}
static void rawgettable() {
lua_Object t = luaL_nonnullarg(1);
lua_Object i = luaL_nonnullarg(2);
lua_pushobject(t);
lua_pushobject(i);
lua_pushobject(lua_rawgettable());
}
static void rawsettable() {
lua_Object t = luaL_nonnullarg(1);
lua_Object i = luaL_nonnullarg(2);
lua_Object v = luaL_nonnullarg(3);
lua_pushobject(t);
lua_pushobject(i);
lua_pushobject(v);
lua_rawsettable();
}
static void settagmethod() {
lua_Object nf = luaL_nonnullarg(3);
lua_pushobject(nf);
lua_pushobject(lua_settagmethod((int32)luaL_check_number(1), luaL_check_string(2)));
}
static void gettagmethod() {
lua_pushobject(lua_gettagmethod((int32)luaL_check_number(1), luaL_check_string(2)));
}
static void seterrormethod() {
lua_Object nf = luaL_functionarg(1);
lua_pushobject(nf);
lua_pushobject(lua_seterrormethod());
}
static void luaI_collectgarbage() {
lua_pushnumber(lua_collectgarbage((int32)luaL_opt_number(1, 0)));
}
/*
** =======================================================
** some DEBUG functions
** =======================================================
*/
#ifdef LUA_DEBUG
static void mem_query() {
lua_pushnumber(totalmem);
lua_pushnumber(numblocks);
}
static void countlist() {
char *s = luaL_check_string(1);
GCnode *l = (s[0] == 't') ? lua_state->roottable.next : (s[0] == 'c') ? lua_state->rootcl.next :
(s[0] == 'p') ? lua_state->rootproto.next : lua_state->rootglobal.next;
int32 i = 0;
while (l) {
i++;
l = l->next;
}
lua_pushnumber(i);
}
static void testC() {
#define getnum(s) ((*s++) - '0')
#define getname(s) (nome[0] = *s++, nome)
static int32 locks[10];
lua_Object reg[10];
char nome[2];
char *s = luaL_check_string(1);
nome[1] = 0;
while (1) {
switch (*s++) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
lua_pushnumber(*(s - 1) - '0');
break;
case 'c':
reg[getnum(s)] = lua_createtable();
break;
case 'C':
{
lua_CFunction f = lua_getcfunction(lua_getglobal(getname(s)));
lua_pushCclosure(f, getnum(s));
break;
}
case 'P':
reg[getnum(s)] = lua_pop();
break;
case 'g':
{
int32 n=getnum(s);
reg[n] = lua_getglobal(getname(s));
break;
}
case 'G':
{
int32 n = getnum(s);
reg[n] = lua_rawgetglobal(getname(s));
break;
}
case 'l':
locks[getnum(s)] = lua_ref(1);
break;
case 'L':
locks[getnum(s)] = lua_ref(0);
break;
case 'r':
{
int32 n = getnum(s);
reg[n] = lua_getref(locks[getnum(s)]);
break;
}
case 'u':
lua_unref(locks[getnum(s)]);
break;
case 'p':
{
int32 n = getnum(s);
reg[n] = lua_getparam(getnum(s));
break;
}
case '=':
lua_setglobal(getname(s));
break;
case 's':
lua_pushstring(getname(s));
break;
case 'o':
lua_pushobject(reg[getnum(s)]);
break;
case 'f':
lua_call(getname(s));
break;
case 'i':
reg[getnum(s)] = lua_gettable();
break;
case 'I':
reg[getnum(s)] = lua_rawgettable();
break;
case 't':
lua_settable();
break;
case 'T':
lua_rawsettable();
break;
default:
luaL_verror("unknown command in `testC': %c", *(s - 1));
}
if (*s == 0)
return;
if (*s++ != ' ')
lua_error("missing ` ' between commands in `testC'");
}
}
#endif
/*
** Internal functions
*/
static struct luaL_reg int_funcs[] = {
#ifdef LUA_COMPAT2_5
{ "setfallback", luaT_setfallback },
#endif
#ifdef LUA_DEBUG
{ "testC", testC },
{ "totalmem", mem_query },
{ "count", countlist },
#endif
{ "assert", luaI_assert },
{ "call", luaI_call },
{ "collectgarbage", luaI_collectgarbage },
{ "copytagmethods", copytagmethods },
{ "dostring", internaldostring },
{ "error", luaI_error },
{ "foreach", foreach },
{ "foreachvar", foreachvar },
{ "getglobal", getglobal },
{ "newtag", newtag },
{ "next", next },
{ "nextvar", nextvar },
{ "print", luaI_print },
{ "rawgetglobal", rawgetglobal },
{ "rawgettable", rawgettable },
{ "rawsetglobal", rawsetglobal },
{ "rawsettable", rawsettable },
{ "seterrormethod", seterrormethod },
{ "setglobal", setglobal },
{ "settagmethod", settagmethod },
{ "gettagmethod", gettagmethod },
{ "settag", settag },
{ "tonumber", tonumber },
{ "tostring", bi_tostring },
{ "tag", luatag },
{ "type", luaI_type },
{ "start_script", start_script },
{ "stop_script", stop_script },
{ "next_script", next_script },
{ "identify_script", identify_script },
{ "pause_scripts", pause_scripts },
{ "unpause_scripts", unpause_scripts },
{ "find_script", find_script },
{ "sleep_for", sleep_for },
{ "break_here", break_here },
{ "pause_script", pause_script },
{ "unpause_script", unpause_script }
};
void luaB_predefine() {
// pre-register mem error messages, to avoid loop when error arises
luaS_newfixedstring(tableEM);
luaS_newfixedstring(memEM);
luaL_openlib(int_funcs, sizeof(int_funcs) / sizeof(int_funcs[0]));
lua_pushstring(LUA_VERSION);
lua_setglobal("_VERSION");
}
} // end of namespace Grim

View File

@@ -0,0 +1,24 @@
/*
** Built-in functions
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LBUILTIN_H
#define GRIM_LBUILTIN_H
namespace Grim {
void luaB_predefine();
void stop_script();
void start_script();
void find_script();
void identify_script();
void next_script();
void break_here();
void sleep_for();
void pause_scripts();
void unpause_scripts();
} // end of namespace Grim
#endif

450
engines/grim/lua/ldo.cpp Normal file
View File

@@ -0,0 +1,450 @@
/*
** Stack and Call structure of Lua
** 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_sprintf
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
#ifdef _MSC_VER
#pragma warning(disable:4611)
#endif
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lgc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lopcodes.h"
#include "engines/grim/lua/lparser.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/ltask.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/luadebug.h"
#include "engines/grim/lua/lundump.h"
#include "engines/grim/lua/lvm.h"
#include "engines/grim/lua/lzio.h"
#include "common/file.h"
#include "common/textconsole.h"
namespace Grim {
#ifndef STACK_LIMIT
#define STACK_LIMIT 6000
#endif
// Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ...
#define EXTRA_STACK 5
/*
** Error messages
*/
void stderrorim() {
fprintf(stderr, "lua error: %s\n", lua_getstring(lua_getparam(1)));
}
#define STACK_UNIT 256
// Initial size for CallInfo array
#define BASIC_CI_SIZE 8
void luaD_init() {
ttype(&errorim) = LUA_T_CPROTO;
fvalue(&errorim) = stderrorim;
}
void luaD_checkstack(int32 n) {
struct Stack *S = &lua_state->stack;
if (S->last-S->top <= n) {
StkId top = S->top-S->stack;
int32 stacksize = (S->last-S->stack) + 1 + STACK_UNIT + n;
S->stack = luaM_reallocvector(S->stack, stacksize, TObject);
S->last = S->stack + (stacksize - 1);
S->top = S->stack + top;
if (stacksize >= STACK_LIMIT) { // stack overflow?
if (lua_stackedfunction(100) == LUA_NOOBJECT) // 100 funcs on stack?
lua_error("Lua2C - C2Lua overflow"); // doesn't look like a rec. loop
else
lua_error("stack size overflow");
}
}
}
/*
** Adjust stack. Set top to the given value, pushing NILs if needed.
*/
void luaD_adjusttop(StkId newtop) {
int32 diff = newtop - (lua_state->stack.top - lua_state->stack.stack);
if (diff <= 0)
lua_state->stack.top += diff;
else {
luaD_checkstack(diff);
while (diff--)
ttype(lua_state->stack.top++) = LUA_T_NIL;
}
}
/*
** Open a hole below "nelems" from the lua_state->stack.top.
*/
void luaD_openstack(int32 nelems) {
luaO_memup(lua_state->stack.top - nelems + 1, lua_state->stack.top - nelems, nelems * sizeof(TObject));
incr_top;
}
void luaD_lineHook(int32 line) {
struct C_Lua_Stack oldCLS = lua_state->Cstack;
StkId old_top = lua_state->Cstack.lua2C = lua_state->Cstack.base = lua_state->stack.top-lua_state->stack.stack;
lua_state->Cstack.num = 0;
(*lua_linehook)(line);
lua_state->stack.top = lua_state->stack.stack + old_top;
lua_state->Cstack = oldCLS;
}
void luaD_callHook(StkId base, TProtoFunc *tf, int32 isreturn) {
if (isreturn)
(*lua_callhook)(LUA_NOOBJECT, "(return)", 0);
else {
TObject *f = lua_state->stack.stack + base - 1;
if (tf)
(*lua_callhook)(Ref(f), tf->fileName->str, tf->lineDefined);
else
(*lua_callhook)(Ref(f), "(C)", -1);
}
}
/*
** Call a C function.
** Cstack.num is the number of arguments; Cstack.lua2C points to the
** first argument. Returns an index to the first result from C.
*/
static StkId callC(lua_CFunction f, StkId base) {
struct C_Lua_Stack *CS = &lua_state->Cstack;
struct C_Lua_Stack oldCLS = *CS;
StkId firstResult;
int32 numarg = (lua_state->stack.top - lua_state->stack.stack) - base;
CS->num = numarg;
CS->lua2C = base;
CS->base = base + numarg; // == top - stack
if (lua_callhook)
luaD_callHook(base, nullptr, 0);
lua_state->callLevelCounter++;
(*f)(); // do the actual call
lua_state->callLevelCounter--;
if (lua_callhook) // func may have changed lua_callhook
luaD_callHook(base, nullptr, 1);
firstResult = CS->base;
*CS = oldCLS;
return firstResult;
}
static StkId callCclosure(struct Closure *cl, lua_CFunction f, StkId base) {
TObject *pbase;
int32 nup = cl->nelems; // number of upvalues
luaD_checkstack(nup);
pbase = lua_state->stack.stack + base; // care: previous call may change this
// open space for upvalues as extra arguments
luaO_memup(pbase+nup, pbase, (lua_state->stack.top - pbase) * sizeof(TObject));
// copy upvalues into stack
memcpy(pbase, cl->consts + 1, nup * sizeof(TObject));
lua_state->stack.top += nup;
return callC(f, base);
}
void luaD_callTM(TObject *f, int32 nParams, int32 nResults) {
luaD_openstack(nParams);
*(lua_state->stack.top - nParams - 1) = *f;
lua_state->preventBreakCounter++;
lua_state->callLevelCounter++;
luaD_call((lua_state->stack.top - lua_state->stack.stack) - nParams, nResults);
lua_state->callLevelCounter--;
lua_state->preventBreakCounter--;
}
int32 luaD_call(StkId base, int32 nResults) {
lua_Task *tmpTask = lua_state->task;
if (!lua_state->task || lua_state->callLevelCounter) {
lua_Task *t = luaM_new(lua_Task);
lua_taskinit(t, lua_state->task, base, nResults);
lua_state->task = t;
} else {
tmpTask = lua_state->prevTask;
}
while (1) {
lua_CFunction function = nullptr;
StkId firstResult = 0;
TObject *funcObj = lua_state->stack.stack + base - 1;
if (ttype(funcObj) == LUA_T_CLOSURE) {
Closure *c = clvalue(funcObj);
TObject *proto = &(c->consts[0]);
ttype(funcObj) = LUA_T_CLMARK;
if (ttype(proto) == LUA_T_CPROTO) {
function = fvalue(funcObj);
firstResult = callCclosure(c, fvalue(proto), base);
} else {
lua_taskresume(lua_state->task, c, tfvalue(proto), base);
firstResult = luaV_execute(lua_state->task);
}
} else if (ttype(funcObj) == LUA_T_PMARK) {
if (!lua_state->task->executed) {
TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
if (ttype(im) == LUA_T_NIL)
lua_error("call expression not a function");
luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
continue;
}
firstResult = luaV_execute(lua_state->task);
} else if (ttype(funcObj) == LUA_T_CMARK) {
if (!lua_state->task->executed) {
TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
if (ttype(im) == LUA_T_NIL)
lua_error("call expression not a function");
luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
continue;
}
} else if (ttype(funcObj) == LUA_T_CLMARK) {
Closure *c = clvalue(funcObj);
TObject *proto = &(c->consts[0]);
if (!lua_state->task->executed) {
TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
if (ttype(im) == LUA_T_NIL)
lua_error("call expression not a function");
luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
continue;
}
if (ttype(proto) != LUA_T_CPROTO)
firstResult = luaV_execute(lua_state->task);
} else if (ttype(funcObj) == LUA_T_PROTO) {
ttype(funcObj) = LUA_T_PMARK;
lua_taskresume(lua_state->task, nullptr, tfvalue(funcObj), base);
firstResult = luaV_execute(lua_state->task);
} else if (ttype(funcObj) == LUA_T_CPROTO) {
ttype(funcObj) = LUA_T_CMARK;
function = fvalue(funcObj);
firstResult = callC(fvalue(funcObj), base);
} else {
TObject *im = luaT_getimbyObj(funcObj, IM_FUNCTION);
if (ttype(im) == LUA_T_NIL)
lua_error("call expression not a function");
luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
continue;
}
if (firstResult <= 0) {
nResults = lua_state->task->aux;
base = -firstResult;
lua_Task *t = luaM_new(lua_Task);
lua_taskinit(t, lua_state->task, base, nResults);
lua_state->task = t;
} else {
nResults = lua_state->task->initResults;
base = lua_state->task->initBase;
if (nResults != MULT_RET)
luaD_adjusttop(firstResult + nResults);
base--;
nResults = lua_state->stack.top - (lua_state->stack.stack + firstResult);
for (int32 i = 0; i < nResults; i++)
*(lua_state->stack.stack + base + i) = *(lua_state->stack.stack + firstResult + i);
lua_state->stack.top -= firstResult - base;
lua_Task *tmp = lua_state->task;
lua_state->task = lua_state->task->next;
luaM_free(tmp);
if (lua_state->task) {
nResults = lua_state->task->initResults;
base = lua_state->task->initBase;
}
if (function == break_here || function == sleep_for) {
if (!lua_state->preventBreakCounter) {
lua_state->prevTask = tmpTask;
return 1;
}
}
}
if (lua_state->task == tmpTask)
break;
}
return 0;
}
static void travstack(struct Stack *S, int32 (*fn)(TObject *)) {
for (StkId i = (S->top - 1) - S->stack; i >= 0; i--)
fn(S->stack + i);
}
/*
** Traverse all objects on lua_state->stack.stack, and all other active stacks
*/
void luaD_travstack(int32(*fn)(TObject *)) {
for (LState *t = lua_rootState; t != nullptr; t = t->next) {
travstack(&t->stack, fn);
}
}
static void message(const char *s) {
TObject im = errorim;
if (ttype(&im) != LUA_T_NIL) {
lua_pushstring(s);
luaD_callTM(&im, 1, 0);
}
}
/*
** Reports an error, and jumps up to the available recover label
*/
void lua_error(const char *s) {
if (s)
message(s);
if (lua_state->errorJmp) {
longjmp(*((jmp_buf *)lua_state->errorJmp), 1);
} else {
fprintf(stderr, "lua: exit(1). Unable to recover\n");
}
exit(1); // exit in both cases, to help compilers with noreturn/longjmp
}
/*
** Call the function at lua_state->Cstack.base, and incorporate results on
** the Lua2C structure.
*/
static void do_callinc(int32 nResults) {
StkId base = lua_state->Cstack.base;
luaD_call(base + 1, nResults);
lua_state->Cstack.lua2C = base; // position of the luaM_new results
lua_state->Cstack.num = (lua_state->stack.top - lua_state->stack.stack) - base; // number of results
lua_state->Cstack.base = base + lua_state->Cstack.num; // incorporate results on lua_state->stack.stack/
}
/*
** Execute a protected call. Assumes that function is at lua_state->Cstack.base and
** parameters are on top of it. Leave nResults on the stack.
*/
int32 luaD_protectedrun(int32 nResults) {
jmp_buf myErrorJmp;
int32 status;
struct C_Lua_Stack oldCLS = lua_state->Cstack;
jmp_buf *oldErr = lua_state->errorJmp;
lua_state->errorJmp = &myErrorJmp;
lua_state->preventBreakCounter++;
lua_Task *tmpTask = lua_state->task;
if (setjmp(myErrorJmp) == 0) {
do_callinc(nResults);
status = 0;
} else { // an error occurred: restore lua_state->Cstack and lua_state->stack.top
lua_state->Cstack = oldCLS;
lua_state->stack.top = lua_state->stack.stack + lua_state->Cstack.base;
while (tmpTask != lua_state->task) {
lua_Task *t = lua_state->task;
lua_state->task = lua_state->task->next;
luaM_free(t);
}
status = 1;
}
lua_state->preventBreakCounter--;
lua_state->errorJmp = oldErr;
return status;
}
/*
** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load
*/
static int32 protectedparser(ZIO *z, int32 bin) {
int32 status;
TProtoFunc *tf;
jmp_buf myErrorJmp;
jmp_buf *oldErr = lua_state->errorJmp;
lua_state->errorJmp = &myErrorJmp;
if (setjmp(myErrorJmp) == 0) {
tf = bin ? luaU_undump1(z) : luaY_parser(z);
status = 0;
} else {
tf = nullptr;
status = 1;
}
lua_state->errorJmp = oldErr;
if (status)
return 1; // error code
if (tf == nullptr)
return 2; // 'natural' end
luaD_adjusttop(lua_state->Cstack.base + 1); // one slot for the pseudo-function
lua_state->stack.stack[lua_state->Cstack.base].ttype = LUA_T_PROTO;
lua_state->stack.stack[lua_state->Cstack.base].value.tf = tf;
luaV_closure(0);
return 0;
}
static int32 do_main(ZIO *z, int32 bin) {
int32 status;
do {
int32 old_blocks = (luaC_checkGC(), nblocks);
status = protectedparser(z, bin);
if (status == 1)
return 1; // error
else if (status == 2)
return 0; // 'natural' end
else {
int32 newelems2 = 2 * (nblocks - old_blocks);
GCthreshold += newelems2;
status = luaD_protectedrun(MULT_RET);
GCthreshold -= newelems2;
}
} while (bin && status == 0);
return status;
}
void luaD_gcIM(TObject *o) {
TObject *im = luaT_getimbyObj(o, IM_GC);
if (ttype(im) != LUA_T_NIL) {
*lua_state->stack.top = *o;
incr_top;
luaD_callTM(im, 1, 0);
}
}
#define SIZE_PREF 20 // size of string prefix to appear in error messages
#define SSIZE_PREF "20"
static void build_name (const char *str, char *name, int size) {
if (str == nullptr || *str == ID_CHUNK)
strcpy(name, "(buffer)");
else {
char *temp;
snprintf(name, size, "(dostring) >> \"%." SSIZE_PREF "s\"", str);
temp = strchr(name, '\n');
if (temp) { // end string after first line
*temp = '"';
*(temp + 1) = 0;
}
}
}
int32 lua_dostring(const char *str) {
return lua_dobuffer(str, strlen(str), nullptr);
}
int32 lua_dobuffer(const char *buff, int32 size, const char *name) {
char newname[SIZE_PREF + 25];
ZIO z;
if (!name) {
build_name(buff, newname, SIZE_PREF + 25);
name = newname;
}
luaZ_mopen(&z, buff, size, name);
int32 status = do_main(&z, buff[0] == ID_CHUNK);
return status;
}
} // end of namespace Grim

45
engines/grim/lua/ldo.h Normal file
View File

@@ -0,0 +1,45 @@
/*
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LDO_H
#define GRIM_LDO_H
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lstate.h"
namespace Grim {
#define MULT_RET 255
/*
** macro to increment stack top.
** There must be always an empty slot at the lua_state->stack.top
*/
#define incr_top { if (lua_state->stack.top >= lua_state->stack.last) luaD_checkstack(1); lua_state->stack.top++; }
// macros to convert from lua_Object to (TObject *) and back
#define Address(lo) ((lo) + lua_state->stack.stack - 1)
#define Ref(st) ((st) - lua_state->stack.stack + 1)
void luaD_init();
void luaD_initthr();
void luaD_adjusttop(StkId newtop);
void luaD_openstack(int32 nelems);
void luaD_lineHook(int32 line);
void luaD_callHook(StkId base, TProtoFunc *tf, int32 isreturn);
void luaD_postret(StkId firstResult);
int32 luaD_call(StkId base, int32 nResults);
void luaD_callTM(TObject *f, int32 nParams, int32 nResults);
int32 luaD_protectedrun(int32 nResults);
void luaD_gcIM(TObject *o);
void luaD_travstack(int32 (*fn)(TObject *));
void luaD_checkstack(int32 n);
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,87 @@
/*
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lstate.h"
namespace Grim {
#define gcsizeproto(p) 5 /* approximate "weight" for a prototype */
#define gcsizeclosure(c) 1 /* approximate "weight" for a closure */
Closure *luaF_newclosure(int32 nelems) {
Closure *c = (Closure *)luaM_malloc(sizeof(Closure) + nelems * sizeof(TObject));
luaO_insertlist(&rootcl, (GCnode *)c);
nblocks += gcsizeclosure(c);
c->nelems = nelems;
return c;
}
TProtoFunc *luaF_newproto() {
TProtoFunc *f = luaM_new(TProtoFunc);
f->code = nullptr;
f->lineDefined = 0;
f->fileName = nullptr;
f->consts = nullptr;
f->nconsts = 0;
f->locvars = nullptr;
luaO_insertlist(&rootproto, (GCnode *)f);
nblocks += gcsizeproto(f);
return f;
}
static void freefunc(TProtoFunc *f) {
luaM_free(f->code);
luaM_free(f->locvars);
luaM_free(f->consts);
luaM_free(f);
}
void luaF_freeproto(TProtoFunc *l) {
while (l) {
TProtoFunc *next = (TProtoFunc *)l->head.next;
nblocks -= gcsizeproto(l);
freefunc(l);
l = next;
}
}
void luaF_freeclosure(Closure *l) {
while (l) {
Closure *next = (Closure *)l->head.next;
nblocks -= gcsizeclosure(l);
luaM_free(l);
l = next;
}
}
/*
** Look for n-th local variable at line "line" in function "func".
** Returns NULL if not found.
*/
char *luaF_getlocalname (TProtoFunc *func, int32 local_number, int32 line) {
int32 count = 0;
char *varname = nullptr;
LocVar *lv = func->locvars;
if (!lv)
return nullptr;
for (; lv->line != -1 && lv->line < line; lv++) {
if (lv->varname) { // register
if (++count == local_number)
varname = lv->varname->str;
} else { // unregister
if (--count < local_number) {
varname = nullptr;
}
}
}
return varname;
}
} // end of namespace Grim

23
engines/grim/lua/lfunc.h Normal file
View File

@@ -0,0 +1,23 @@
/*
** Lua Function structures
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LFUNC_H
#define GRIM_LFUNC_H
#include "engines/grim/lua/lobject.h"
namespace Grim {
TProtoFunc *luaF_newproto();
Closure *luaF_newclosure(int32 nelems);
void luaF_freeproto(TProtoFunc *l);
void luaF_freeclosure(Closure *l);
char *luaF_getlocalname (TProtoFunc *func, int32 local_number, int32 line);
} // end of namespace Grim
#endif

259
engines/grim/lua/lgc.cpp Normal file
View File

@@ -0,0 +1,259 @@
/*
** Garbage Collector
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lgc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/ltable.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
static int32 markobject (TObject *o);
/*
** =======================================================
** REF mechanism
** =======================================================
*/
int32 luaC_ref(TObject *o, int32 lock) {
int32 ref;
if (ttype(o) == LUA_T_NIL)
ref = -1; // special ref for nil
else {
for (ref = 0; ref < refSize; ref++)
if (refArray[ref].status == FREE)
goto found;
// no more empty spaces
{
int32 oldSize = refSize;
refSize = luaM_growvector(&refArray, refSize, struct ref, refEM, MAX_WORD);
for (ref = oldSize; ref < refSize; ref++) {
refArray[ref].status = FREE;
refArray[ref].o.ttype = LUA_T_NIL;
refArray[ref].o.value.ts = nullptr;
}
ref = oldSize;
}
found:
refArray[ref].o = *o;
refArray[ref].status = lock ? LOCK : HOLD;
}
return ref;
}
void lua_unref(int32 r) {
if (r >= 0 && r < refSize) {
refArray[r].status = FREE;
refArray[r].o.ttype = LUA_T_NIL;
refArray[r].o.value.ts = nullptr;
}
}
TObject* luaC_getref(int32 r) {
if (r == -1)
return &luaO_nilobject;
if (r >= 0 && r < refSize && (refArray[r].status == LOCK || refArray[r].status == HOLD))
return &refArray[r].o;
else
return nullptr;
}
static void travlock() {
int32 i;
for (i = 0; i < refSize; i++) {
if (refArray[i].status == LOCK) {
markobject(&refArray[i].o);
}
}
}
static int32 ismarked(TObject *o) {
// valid only for locked objects
switch (o->ttype) {
case LUA_T_STRING:
return o->value.ts->head.marked;
case LUA_T_ARRAY:
return o->value.a->head.marked;
case LUA_T_CLOSURE:
return o->value.cl->head.marked;
case LUA_T_PROTO:
return o->value.tf->head.marked;
#ifdef LUA_DEBUG
case LUA_T_LINE:
case LUA_T_CLMARK:
case LUA_T_CMARK:
case LUA_T_PMARK:
LUA_INTERNALERROR("internal error");
#endif
default: // nil, number or cproto
return 1;
}
}
static void invalidaterefs() {
for (int32 i = 0; i < refSize; i++)
if (refArray[i].status == HOLD && !ismarked(&refArray[i].o))
refArray[i].status = COLLECTED;
}
void luaC_hashcallIM(Hash *l) {
TObject t;
ttype(&t) = LUA_T_ARRAY;
for (; l; l = (Hash *)l->head.next) {
avalue(&t) = l;
luaD_gcIM(&t);
}
}
void luaC_strcallIM(TaggedString *l) {
TObject o;
ttype(&o) = LUA_T_USERDATA;
for (; l; l=(TaggedString *)l->head.next) {
if (l->constindex == -1) { // is userdata?
tsvalue(&o) = l;
luaD_gcIM(&o);
}
}
}
static GCnode *listcollect(GCnode *l) {
GCnode *frees = nullptr;
while (l) {
GCnode *next = l->next;
l->marked = 0;
while (next && !next->marked) {
l->next = next->next;
next->next = frees;
frees = next;
next = l->next;
}
l = next;
}
return frees;
}
static void strmark(TaggedString *s) {
if (!s->head.marked)
s->head.marked = 1;
}
static void protomark(TProtoFunc *f) {
if (!f->head.marked) {
LocVar *v = f->locvars;
f->head.marked = 1;
if (f->fileName)
strmark(f->fileName);
for (int32 i = 0; i < f->nconsts; i++)
markobject(&f->consts[i]);
if (v) {
for (; v->line != -1; v++) {
if (v->varname)
strmark(v->varname);
}
}
}
}
static void closuremark(Closure *f) {
if (!f->head.marked) {
f->head.marked = 1;
for (int32 i = f->nelems; i >= 0; i--)
markobject(&f->consts[i]);
}
}
static void hashmark(Hash *h) {
if (!h->head.marked) {
h->head.marked = 1;
for (int32 i = 0; i < nhash(h); i++) {
Node *n = node(h, i);
if (ttype(ref(n)) != LUA_T_NIL) {
markobject(&n->ref);
markobject(&n->val);
}
}
}
}
static void globalmark() {
TaggedString *g;
for (g = (TaggedString *)rootglobal.next; g; g = (TaggedString *)g->head.next){
if (g->globalval.ttype != LUA_T_NIL) {
markobject(&g->globalval);
strmark(g); // cannot collect non nil global variables
}
}
}
static int32 markobject(TObject *o) {
switch (ttype(o)) {
case LUA_T_STRING:
strmark(tsvalue(o));
break;
case LUA_T_ARRAY:
hashmark(avalue(o));
break;
case LUA_T_CLOSURE:
case LUA_T_CLMARK:
closuremark(o->value.cl);
break;
case LUA_T_PROTO:
case LUA_T_PMARK:
protomark(o->value.tf);
break;
default:
break; // numbers, cprotos, etc
}
return 0;
}
static void markall() {
luaD_travstack(markobject); // mark stack objects
globalmark(); // mark global variable values and names
travlock(); // mark locked objects
luaT_travtagmethods(markobject); // mark fallbacks
}
int32 lua_collectgarbage(int32 limit) {
int32 recovered = nblocks; // to subtract nblocks after gc
Hash *freetable;
TaggedString *freestr;
TProtoFunc *freefunc;
Closure *freeclos;
markall();
invalidaterefs();
freestr = luaS_collector();
freetable = (Hash *)listcollect(&roottable);
freefunc = (TProtoFunc *)listcollect(&rootproto);
freeclos = (Closure *)listcollect(&rootcl);
GCthreshold *= 4; // to avoid GC during GC
luaC_hashcallIM(freetable); // GC tag methods for tables
luaC_strcallIM(freestr); // GC tag methods for userdata
luaD_gcIM(&luaO_nilobject); // GC tag method for nil (signal end of GC)
luaH_free(freetable);
luaS_free(freestr);
luaF_freeproto(freefunc);
luaF_freeclosure(freeclos);
recovered = recovered - nblocks;
GCthreshold = (limit == 0) ? 2 * nblocks : nblocks + limit;
return recovered;
}
void luaC_checkGC() {
if (nblocks >= GCthreshold)
lua_collectgarbage(0);
}
} // end of namespace Grim

22
engines/grim/lua/lgc.h Normal file
View File

@@ -0,0 +1,22 @@
/*
** Garbage Collector
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LGC_H
#define GRIM_LGC_H
#include "lobject.h"
namespace Grim {
void luaC_checkGC();
TObject* luaC_getref(int32 r);
int32 luaC_ref(TObject *o, int32 lock);
void luaC_hashcallIM(Hash *l);
void luaC_strcallIM(TaggedString *l);
} // end of namespace Grim
#endif

466
engines/grim/lua/liolib.cpp Normal file
View File

@@ -0,0 +1,466 @@
/*
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
#define FORBIDDEN_SYMBOL_EXCEPTION_fseek
#define FORBIDDEN_SYMBOL_EXCEPTION_sprintf
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
#include "common/savefile.h"
#include "common/fs.h"
#include "common/system.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/luadebug.h"
#include "engines/grim/lua/lualib.h"
#include "base/commandLine.h"
#include "engines/grim/resource.h"
namespace Grim {
#define CLOSEDTAG 2
#define IOTAG 1
#define FIRSTARG 3 // 1st and 2nd are upvalues
#define FINPUT "_INPUT"
#define FOUTPUT "_OUTPUT"
LuaFile *g_stderr;
static int32 s_id = 0;
Common::HashMap<int32, LuaFile *> *g_files;
LuaFile::LuaFile() : _in(nullptr), _out(nullptr), _stdin(false), _stdout(false), _stderr(false) {
}
LuaFile::~LuaFile() {
close();
}
void LuaFile::close() {
delete _in;
delete _out;
_in = nullptr;
_out = nullptr;
_stdin = _stdout = _stderr = false;
}
bool LuaFile::isOpen() const {
return _in || _out || _stdin || stdout || stderr;
}
uint32 LuaFile::read(void *buf, uint32 len) {
if (_stdin) {
return fread(buf, len, 1, stdin);
} else if (_in) {
return _in->read(buf, len);
} else
assert(0);
return 0;
}
uint32 LuaFile::write(const char *buf, uint32 len) {
if (_stdin)
error("LuaFile::write() not allowed on stdin");
if (_in)
error("LuaFile::write() not allowed on in");
if (_stdout) {
return fwrite(buf, len, 1, stdout);
} else if (_stderr) {
return fwrite(buf, len, 1, stderr);
} else if (_out) {
return _out->write(buf, len);
} else
assert(0);
return 0;
}
void LuaFile::seek(int32 pos, int whence) {
if (_stdin) {
fseek(stdin, pos, whence);
} else if (_in) {
_in->seek(pos, whence);
} else
assert(0);
}
static int32 gettag(int32 i) {
return (int32)lua_getnumber(lua_getparam(i));
}
static void pushresult(int32 i) {
if (i)
lua_pushuserdata(0);
else {
lua_pushnil();
lua_pushstring("File I/O error.");
}
}
static int32 ishandler(lua_Object f) {
if (lua_isuserdata(f)) {
if (lua_tag(f) == gettag(CLOSEDTAG))
lua_error("cannot access a closed file");
return lua_tag(f) == gettag(IOTAG);
}
else return 0;
}
static LuaFile *getfile(int32 id) {
if (g_files->contains(id)) {
return (*g_files)[id];
}
return nullptr;
}
static LuaFile *getfile(const char *name) {
lua_Object f = lua_getglobal(name);
if (!ishandler(f))
luaL_verror("global variable `%.50s' is not a file handle", name);
return getfile(lua_getuserdata(f));
}
static LuaFile *getfileparam(const char *name, int32 *arg) {
lua_Object f = lua_getparam(*arg);
if (ishandler(f)) {
(*arg)++;
return getfile(lua_getuserdata(f));
} else
return getfile(name);
}
static void closefile(const char *name) {
LuaFile *f = getfile(name);
f->close();
lua_pushobject(lua_getglobal(name));
lua_settag(gettag(CLOSEDTAG));
}
static void setfile(int32 id, const char *name, int32 tag) {
lua_pushusertag(id, tag);
lua_setglobal(name);
}
static void setreturn(int32 id, const char *name) {
int32 tag = gettag(IOTAG);
setfile(id, name, tag);
lua_pushusertag(id, tag);
}
static int32 addfile(LuaFile *f) {
++s_id;
(*g_files)[s_id] = f;
return s_id;
}
static void io_readfrom() {
lua_Object f = lua_getparam(FIRSTARG);
if (f == LUA_NOOBJECT) {
if (getfile(FINPUT) != getfile(1)) {
closefile(FINPUT);
setreturn(1, FINPUT);
}
} else if (lua_tag(f) == gettag(IOTAG)) {
int32 id = lua_getuserdata(f);
LuaFile *current = getfile(id);
if (!current) {
pushresult(0);
return;
}
setreturn(id, FINPUT);
} else {
const char *s = luaL_check_string(FIRSTARG);
Common::String fileName = Common::lastPathComponent(s, '\\');
Common::SeekableReadStream *inFile = nullptr;
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
inFile = saveFileMan->openForLoading(fileName);
if (!inFile) {
inFile = g_resourceloader->openNewStreamFile(s);
}
if (inFile) {
LuaFile *current = new LuaFile();
current->_in = inFile;
current->_filename = s;
setreturn(addfile(current), FINPUT);
} else {
warning("liolib.cpp, io_readfrom(): Could not open file %s", s);
pushresult(0);
}
}
}
static void io_writeto() {
lua_Object f = lua_getparam(FIRSTARG);
if (f == LUA_NOOBJECT) {
if (getfile(FOUTPUT) != getfile(2)) {
closefile(FOUTPUT);
setreturn(2, FOUTPUT);
}
} else if (lua_tag(f) == gettag(IOTAG)) {
int32 id = lua_getuserdata(f);
LuaFile *current = getfile(id);
if (!current->isOpen()) {
pushresult(0);
return;
}
setreturn(id, FOUTPUT);
} else {
Common::String s = Common::lastPathComponent(luaL_check_string(FIRSTARG), '\\');
LuaFile *current;
Common::WriteStream *outFile = nullptr;
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
outFile = saveFileMan->openForSaving(s, false);
if (!outFile) {
pushresult(0);
return;
}
current = new LuaFile();
current->_out = outFile;
current->_filename = s;
setreturn(addfile(current), FOUTPUT);
}
}
static void io_appendto() {
Common::String s = Common::lastPathComponent(luaL_check_string(FIRSTARG), '\\');
Common::SeekableReadStream *inFile = nullptr;
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
inFile = saveFileMan->openForLoading(s);
if (!inFile) {
pushresult(0);
return;
}
int size = inFile->size();
byte *buf = new byte[size];
inFile->read(buf, size);
delete inFile;
Common::WriteStream *outFile = nullptr;
outFile = saveFileMan->openForSaving(s);
if (!outFile)
pushresult(0);
else {
outFile->write(buf, size);
LuaFile *current = new LuaFile();
current->_out = outFile;
current->_filename = s;
setreturn(addfile(current), FOUTPUT);
}
delete[] buf;
}
#define NEED_OTHER (EOF - 1) // just some flag different from EOF
static void io_read() {
int32 arg = FIRSTARG;
LuaFile *f = (LuaFile *)getfileparam(FINPUT, &arg);
char *buff;
const char *p = luaL_opt_string(arg, "[^\n]*{\n}");
int inskip = 0; // to control {skips}
int c = NEED_OTHER;
luaL_resetbuffer();
while (*p) {
if (*p == '{') {
inskip++;
p++;
} else if (*p == '}') {
if (inskip == 0)
lua_error("unbalanced braces in read pattern");
inskip--;
p++;
} else {
const char *ep; // get what is next
int m; // match result
if (c == NEED_OTHER) {
char z;
if (f->read(&z, 1) != 1)
c = EOF;
else
c = z;
}
m = luaI_singlematch((c == EOF) ? 0 : (char)c, p, &ep);
if (m) {
if (inskip == 0)
luaL_addchar(c);
c = NEED_OTHER;
}
switch (*ep) {
case '*': // repetition
if (!m)
p = ep + 1; // else stay in (repeat) the same item
break;
case '?': // optional
p = ep + 1; // continues reading the pattern
break;
default:
if (m)
p = ep; // continues reading the pattern
else
goto break_while; // pattern fails
}
}
}
break_while:
if (c >= 0) // not EOF nor NEED_OTHER?
f->seek(-1, SEEK_CUR);
luaL_addchar(0);
buff = luaL_buffer();
if (*buff != 0 || *p == 0) // read something or did not fail?
lua_pushstring(buff);
}
static void io_write() {
int32 arg = FIRSTARG;
LuaFile *f = (LuaFile *)getfileparam(FOUTPUT, &arg);
int32 status = 1;
const char *s;
while ((s = luaL_opt_string(arg++, nullptr)) != nullptr)
status = status && ((int32)f->write(s, strlen(s)) != EOF);
pushresult(status);
}
static void io_date() {
TimeDate t;
char b[BUFSIZ];
g_system->getTimeAndDate(t);
snprintf(b, BUFSIZ, "%02d.%02d.%d %02d:%02d.%02d", t.tm_mday, t.tm_mon + 1, 1900 + t.tm_year, t.tm_hour, t.tm_min, t.tm_sec);
lua_pushstring(b);
}
static void io_exit() {
lua_Object o = lua_getparam(1);
exit((int)lua_isnumber(o) ? (int)lua_getnumber(o) : 1);
}
static void lua_printstack() {
int32 level = 1; // skip level 0 (it's this function)
lua_Object func;
char buf[256];
while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) {
const char *name;
int32 currentline;
const char *filename;
int32 linedefined;
lua_funcinfo(func, &filename, &linedefined);
snprintf(buf, 256, (level == 2) ? "Active Stack:\n\t" : "\t");
g_stderr->write(buf, strlen(buf));
switch (*lua_getobjname(func, &name)) {
case 'g':
snprintf(buf, 256, "function %s", name);
break;
case 't':
snprintf(buf, 256, "`%s' tag method", name);
break;
default:
{
if (linedefined == 0)
snprintf(buf, 256, "main of %s", filename);
else if (linedefined < 0)
snprintf(buf, 256, "%s", filename);
else
snprintf(buf, 256, "function (%s:%d)", filename, (int)linedefined);
filename = nullptr;
}
}
g_stderr->write(buf, strlen(buf));
if ((currentline = lua_currentline(func)) > 0) {
snprintf(buf, 256, " at line %d", (int)currentline);
g_stderr->write(buf, strlen(buf));
}
if (filename) {
snprintf(buf, 256, " [in file %s]", filename);
g_stderr->write(buf, strlen(buf));
}
snprintf(buf, 256, "\n");
g_stderr->write(buf, strlen(buf));
}
}
static void errorfb() {
char buf[256];
snprintf(buf, 256, "lua: %s\n", lua_getstring(lua_getparam(1)));
g_stderr->write(buf, strlen(buf));
lua_printstack();
}
static struct luaL_reg iolib[] = {
{ "date", io_date },
{ "exit", io_exit },
{ "print_stack", errorfb }
};
static struct luaL_reg iolibtag[] = {
{ "readfrom", io_readfrom },
{ "writeto", io_writeto },
{ "appendto", io_appendto },
{ "read", io_read },
{ "write", io_write }
};
static void openwithtags() {
int32 iotag = lua_newtag();
int32 closedtag = lua_newtag();
for (uint32 i = 0; i < sizeof(iolibtag) / sizeof(iolibtag[0]); i++) {
// put both tags as upvalues for these functions
lua_pushnumber(iotag);
lua_pushnumber(closedtag);
lua_pushCclosure(iolibtag[i].func, 2);
lua_setglobal(iolibtag[i].name);
}
LuaFile* f;
f = new LuaFile();
f->_stdin = true;
setfile(addfile(f), FINPUT, iotag);
f = new LuaFile();
f->_stdout = true;
setfile(addfile(f), FOUTPUT, iotag);
f = new LuaFile();
f->_stdin = true;
setfile(addfile(f), "_STDIN", iotag);
f = new LuaFile();
f->_stdout = true;
setfile(addfile(f), "_STDOUT", iotag);
g_stderr = new LuaFile();
g_stderr->_stderr = true;
setfile(addfile(g_stderr), "_STDERR", iotag);
}
void lua_iolibopen() {
g_files = new Common::HashMap<int32, LuaFile *>();
luaL_openlib(iolib, (sizeof(iolib) / sizeof(iolib[0])));
luaL_addlibtolist(iolibtag, (sizeof(iolibtag) / sizeof(iolibtag[0])));
openwithtags();
lua_pushcfunction(errorfb);
lua_seterrormethod();
}
void lua_iolibclose() {
for (Common::HashMap<int32, LuaFile *>::iterator it = g_files->begin(); it != g_files->end(); ++it) {
delete it->_value;
}
delete g_files;
}
} // end of namespace Grim

446
engines/grim/lua/llex.cpp Normal file
View File

@@ -0,0 +1,446 @@
/*
** Lexical Analizer
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "common/util.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/llex.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lparser.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lstx.h"
#include "engines/grim/lua/luadebug.h"
#include "engines/grim/lua/lzio.h"
namespace Grim {
int32 lua_debug = 0;
#define next(LS) (LS->current = zgetc(LS->lex_z))
static struct {
const char *name;
int token;
} reserved [] = {
{"and", AND}, {"do", DO}, {"else", ELSE}, {"elseif", ELSEIF},
{"end", END}, {"function", FUNCTION}, {"if", IF}, {"local", LOCAL},
{"nil", NIL}, {"not", NOT}, {"or", OR}, {"repeat", REPEAT},
{"return", RETURN}, {"then", THEN}, {"until", UNTIL}, {"while", WHILE}
};
void luaX_init() {
uint32 i;
for (i = 0; i < (sizeof(reserved) / sizeof(reserved[0])); i++) {
TaggedString *ts = luaS_new(reserved[i].name);
ts->head.marked = reserved[i].token; /* reserved word (always > 255) */
}
}
static void firstline(LexState *LS) {
int32 c = zgetc(LS->lex_z);
if (c == '#') {
LS->linenumber++;
while ((c = zgetc(LS->lex_z)) != '\n' && c != EOZ) ; // skip first line
}
zungetc(LS->lex_z);
}
void luaX_setinput(ZIO *z) {
LexState *LS = lua_state->lexstate;
LS->current = '\n';
LS->linelasttoken = 0;
LS->linenumber = 0;
LS->iflevel = 0;
LS->ifstate[0].skip = 0;
LS->ifstate[0].elsepart = 1; // to avoid a free $else
LS->lex_z = z;
firstline(LS);
luaL_resetbuffer();
}
/*
** =======================================================
** PRAGMAS
** =======================================================
*/
#define PRAGMASIZE 20
static void skipspace(LexState *LS) {
while (LS->current == ' ' || LS->current == '\t' || LS->current == '\r')
next(LS);
}
static int32 checkcond(char *buff) {
static const char *opts[] = { "nil", "1", nullptr };
int32 i = luaO_findstring(buff, opts);
if (i >= 0)
return i;
else if (Common::isAlpha((byte)buff[0]) || buff[0] == '_')
return luaS_globaldefined(buff);
else {
luaY_syntaxerror("invalid $if condition", buff);
return 0; // to avoid warnings
}
}
static void readname(LexState *LS, char *buff) {
int32 i = 0;
skipspace(LS);
while (Common::isAlnum(LS->current) || LS->current == '_') {
if (i >= PRAGMASIZE) {
buff[PRAGMASIZE] = 0;
luaY_syntaxerror("pragma too long", buff);
}
buff[i++] = LS->current;
next(LS);
}
buff[i] = 0;
}
static void inclinenumber (LexState *LS);
static void ifskip (LexState *LS) {
while (LS->ifstate[LS->iflevel].skip) {
if (LS->current == '\n')
inclinenumber(LS);
else if (LS->current == EOZ)
luaY_syntaxerror("input ends inside a $if", "");
else
next(LS);
}
}
static void inclinenumber (LexState *LS) {
static const char *pragmas [] =
{ "debug", "nodebug", "endinput", "end", "ifnot", "if", "else", nullptr };
next(LS); // skip '\n'
++LS->linenumber;
if (LS->current == '$') { // is a pragma?
char buff[PRAGMASIZE + 1];
int32 ifnot = 0;
int32 skip = LS->ifstate[LS->iflevel].skip;
next(LS); // skip $
readname(LS, buff);
switch (luaO_findstring(buff, pragmas)) {
case 0: // debug
if (!skip)
lua_debug = 1;
break;
case 1: // nodebug
if (!skip)
lua_debug = 0;
break;
case 2: // endinput
if (!skip) {
LS->current = EOZ;
LS->iflevel = 0; // to allow $endinput inside a $if
}
break;
case 3: // end
if (LS->iflevel-- == 0)
luaY_syntaxerror("unmatched $end", "$end");
break;
case 4: // ifnot
ifnot = 1;
// fall through
case 5: // if
if (LS->iflevel == MAX_IFS - 1)
luaY_syntaxerror("too many nested $ifs", "$if");
readname(LS, buff);
LS->iflevel++;
LS->ifstate[LS->iflevel].elsepart = 0;
LS->ifstate[LS->iflevel].condition = checkcond(buff) ? !ifnot : ifnot;
LS->ifstate[LS->iflevel].skip = skip || !LS->ifstate[LS->iflevel].condition;
break;
case 6: // else
if (LS->ifstate[LS->iflevel].elsepart)
luaY_syntaxerror("unmatched $else", "$else");
LS->ifstate[LS->iflevel].elsepart = 1;
LS->ifstate[LS->iflevel].skip = LS->ifstate[LS->iflevel - 1].skip || LS->ifstate[LS->iflevel].condition;
break;
default:
luaY_syntaxerror("unknown pragma", buff);
}
skipspace(LS);
if (LS->current == '\n') // pragma must end with a '\n' ...
inclinenumber(LS);
else if (LS->current != EOZ) // or eof
luaY_syntaxerror("invalid pragma format", buff);
ifskip(LS);
}
}
/*
** =======================================================
** LEXICAL ANALIZER
** =======================================================
*/
#define save(c) luaL_addchar(c)
#define save_and_next(LS) (save(LS->current), next(LS))
char *luaX_lasttoken() {
save(0);
return luaL_buffer();
}
static int read_long_string(LexState *LS, YYSTYPE *l) {
int cont = 0;
while (1) {
switch (LS->current) {
case EOZ:
save(0);
return WRONGTOKEN;
case '[':
save_and_next(LS);
if (LS->current == '[') {
cont++;
save_and_next(LS);
}
continue;
case ']':
save_and_next(LS);
if (LS->current == ']') {
if (cont == 0)
goto endloop;
cont--;
save_and_next(LS);
}
continue;
case '\n':
save('\n');
inclinenumber(LS);
continue;
default:
save_and_next(LS);
}
}
endloop:
save_and_next(LS); // pass the second ']'
Mbuffer[Mbuffnext - 2] = 0; // erases ']]'
l->pTStr = luaS_new(Mbuffbase + 2);
Mbuffer[Mbuffnext - 2] = ']'; // restores ']]'
return STRING;
}
/* to avoid warnings; this declaration cannot be public since YYSTYPE
** cannot be visible in llex.h (otherwise there is an error, since
** the parser body redefines it!)
*/
int32 luaY_lex(YYSTYPE *l);
int32 luaY_lex(YYSTYPE *l) {
LexState *LS = lua_state->lexstate;
double a;
luaL_resetbuffer();
if (lua_debug)
luaY_codedebugline(LS->linelasttoken);
LS->linelasttoken = LS->linenumber;
while (1) {
switch (LS->current) {
case ' ':
case '\t':
case '\r': // CR: to avoid problems with DOS
next(LS);
continue;
case '\n':
inclinenumber(LS);
LS->linelasttoken = LS->linenumber;
continue;
case '-':
save_and_next(LS);
if (LS->current != '-')
return '-';
do {
next(LS);
} while (LS->current != '\n' && LS->current != EOZ);
luaL_resetbuffer();
continue;
case '[':
save_and_next(LS);
if (LS->current != '[')
return '[';
else {
save_and_next(LS); // pass the second '['
return read_long_string(LS, l);
}
case '=':
save_and_next(LS);
if (LS->current != '=')
return '=';
else {
save_and_next(LS);
return EQ;
}
case '<':
save_and_next(LS);
if (LS->current != '=')
return '<';
else {
save_and_next(LS);
return LE;
}
case '>':
save_and_next(LS);
if (LS->current != '=')
return '>';
else {
save_and_next(LS);
return GE;
}
case '~':
save_and_next(LS);
if (LS->current != '=')
return '~';
else {
save_and_next(LS);
return NE;
}
case '"':
case '\'':
{
int32 del = LS->current;
save_and_next(LS);
while (LS->current != del) {
switch (LS->current) {
case EOZ:
case '\n':
save(0);
return WRONGTOKEN;
case '\\':
next(LS); // do not save the '\'
switch (LS->current) {
case 'n':
save('\n');
next(LS);
break;
case 't':
save('\t');
next(LS);
break;
case 'r':
save('\r');
next(LS);
break;
case '\n':
save('\n');
inclinenumber(LS);
break;
default :
save_and_next(LS); break;
}
break;
default:
save_and_next(LS);
}
}
next(LS); // skip delimiter
save(0);
l->pTStr = luaS_new(Mbuffbase + 1);
Mbuffer[Mbuffnext - 1] = del; // restore delimiter
return STRING;
}
case '.':
save_and_next(LS);
if (LS->current == '.') {
save_and_next(LS);
if (LS->current == '.') {
save_and_next(LS);
return DOTS; // ...
} else
return CONC; // ..
} else if (!Common::isDigit(LS->current))
return '.';
// LS->current is a digit: goes through to number/
a = 0.0;
goto fraction;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
a = 0.0;
do {
a = 10.0 * a + (LS->current - '0');
save_and_next(LS);
} while (Common::isDigit(LS->current));
if (LS->current == '.') {
save_and_next(LS);
if (LS->current == '.') {
save(0);
luaY_error("ambiguous syntax (decimal point x string concatenation)");
}
}
fraction:
{
double da = 0.1;
while (Common::isDigit(LS->current)) {
a += (LS->current - '0') * da;
da /= 10.0;
save_and_next(LS);
}
if (toupper(LS->current) == 'E') {
int32 e = 0;
int32 neg;
double ea;
save_and_next(LS);
neg = (LS->current == '-');
if (LS->current == '+' || LS->current == '-')
save_and_next(LS);
if (!Common::isDigit(LS->current)) {
save(0);
return WRONGTOKEN;
}
do {
e = 10 * e + (LS->current - '0');
save_and_next(LS);
} while (Common::isDigit(LS->current));
for (ea = neg ? 0.1 : 10.0; e > 0; e >>= 1) {
if (e & 1)
a *= ea;
ea *= ea;
}
}
l->vReal = a;
return NUMBER;
}
case EOZ:
save(0);
if (LS->iflevel > 0)
luaY_syntaxerror("input ends inside a $if", "");
return 0;
default:
if (LS->current != '_' && !Common::isAlpha(LS->current)) {
int32 c = LS->current;
save_and_next(LS);
return c;
} else { // identifier or reserved word
TaggedString *ts;
do {
save_and_next(LS);
} while (Common::isAlnum(LS->current) || LS->current == '_');
save(0);
ts = luaS_new(Mbuffbase);
if (ts->head.marked >= 255)
return ts->head.marked; // reserved word
l->pTStr = ts;
return NAME;
}
}
}
}
} // end of namespace Grim

40
engines/grim/lua/llex.h Normal file
View File

@@ -0,0 +1,40 @@
/*
** Lexical Analizer
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LLEX_H
#define GRIM_LLEX_H
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lzio.h"
namespace Grim {
#define MAX_IFS 5
// "ifstate" keeps the state of each nested $if the lexical is dealing with.
struct ifState {
int32 elsepart; // true if its in the $else part
int32 condition; // true if $if condition is true
int32 skip; // true if part must be skipped
};
typedef struct LexState {
int32 current; // look ahead character
zio *lex_z; // input stream
int32 linenumber; // input line counter
int linelasttoken; /* line where last token was read */
int lastline; /* last line wherein a SETLINE was generated */
int32 iflevel; // level of nested $if's (for lexical analysis)
ifState ifstate[MAX_IFS];
} LexState;
void luaX_init();
void luaX_setinput(ZIO *z);
char *luaX_lasttoken();
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,153 @@
/*
** Lua standard mathematical library
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_rand
#define FORBIDDEN_SYMBOL_EXCEPTION_srand
#include "common/scummsys.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/lualib.h"
namespace Grim {
#define FROMRAD(a) ((a) * (180.0 / (float)M_PI))
#define TORAD(a) ((a) * ((float)M_PI / 180.0))
static void math_abs() {
float d = luaL_check_number(1);
if (d < 0)
d = -d;
lua_pushnumber(d);
}
static void math_sin() {
lua_pushnumber(sin(TORAD(luaL_check_number(1))));
}
static void math_cos() {
lua_pushnumber(cos(TORAD(luaL_check_number(1))));
}
static void math_tan() {
lua_pushnumber(tan(TORAD(luaL_check_number(1))));
}
static void math_asin() {
lua_pushnumber(FROMRAD(asin(luaL_check_number(1))));
}
static void math_acos() {
lua_pushnumber(FROMRAD(acos(luaL_check_number(1))));
}
static void math_atan() {
lua_pushnumber(FROMRAD(atan(luaL_check_number(1))));
}
static void math_ceil() {
lua_pushnumber(ceil(luaL_check_number(1)));
}
static void math_floor() {
lua_pushnumber(floor(luaL_check_number(1)));
}
static void math_mod() {
lua_pushnumber(fmod(luaL_check_number(1), luaL_check_number(2)));
}
static void math_sqrt() {
lua_pushnumber(sqrt(luaL_check_number(1)));
}
static void math_pow() {
lua_pushnumber(pow(luaL_check_number(1), luaL_check_number(2)));
}
static void math_deg() {
lua_pushnumber(luaL_check_number(1) * (180.0 / (float)M_PI));
}
static void math_rad() {
lua_pushnumber(luaL_check_number(1) * ((float)M_PI / 180.0));
}
static void math_min() {
int32 i = 1;
float dmin = luaL_check_number(i);
while (lua_getparam(++i) != LUA_NOOBJECT) {
float d = luaL_check_number(i);
if (d < dmin)
dmin = d;
}
lua_pushnumber(dmin);
}
static void math_max() {
int32 i = 1;
float dmax = luaL_check_number(i);
while (lua_getparam(++i) != LUA_NOOBJECT) {
float d = luaL_check_number(i);
if (d > dmax)
dmax = d;
}
lua_pushnumber(dmax);
}
static void math_random() {
float r = (float)(rand() % RAND_MAX) / (float)RAND_MAX;
float l = luaL_opt_number(1, 0);
if (l == 0)
lua_pushnumber(r);
else
lua_pushnumber((int32)(r * l) + 1);
}
static void math_randomseed() {
srand((unsigned int)luaL_check_number(1));
}
static struct luaL_reg mathlib[] = {
{ "abs", math_abs},
{ "sin", math_sin},
{ "cos", math_cos},
{ "tan", math_tan},
{ "asin", math_asin},
{ "acos", math_acos},
{ "atan", math_atan},
{ "ceil", math_ceil},
{ "floor", math_floor},
{ "mod", math_mod},
{ "sqrt", math_sqrt},
{ "min", math_min},
{ "max", math_max},
{ "deg", math_deg},
{ "rad", math_rad},
{ "random", math_random},
{ "randomseed", math_randomseed}
};
static luaL_reg powFunc[] = {
{ "math_pow", math_pow }
};
/*
** Open math library
*/
void lua_mathlibopen() {
luaL_openlib(mathlib, (sizeof(mathlib) / sizeof(mathlib[0])));
luaL_addlibtolist(powFunc, (sizeof(powFunc) / sizeof(powFunc[0])));
lua_pushstring("deg");
lua_setglobal("_TRIGMODE");
lua_pushcfunction(math_pow);
lua_pushnumber(0); // to get its tag
lua_settagmethod(lua_tag(lua_pop()), "pow");
lua_pushnumber((float)M_PI);
lua_setglobal("PI");
}
} // end of namespace Grim

90
engines/grim/lua/lmem.cpp Normal file
View File

@@ -0,0 +1,90 @@
/*
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
int32 luaM_growaux(void **block, int32 nelems, int32 size, const char *errormsg, int32 limit) {
if (nelems >= limit)
lua_error(errormsg);
nelems = (nelems == 0) ? 32 : nelems * 2;
if (nelems > limit)
nelems = limit;
*block = luaM_realloc(*block, nelems * size);
return (int32)nelems;
}
#ifndef LUA_DEBUG
/*
** generic allocation routine.
** real ANSI systems do not need some of these tests,
** since realloc(NULL, s)==malloc(s) and realloc(b, 0)==free(b).
** But some systems (e.g. Sun OS) are not that ANSI...
*/
void *luaM_realloc(void *block, int32 size) {
if (size == 0) {
free(block);
return nullptr;
}
block = block ? realloc(block, size) : malloc(size);
if (!block)
lua_error(memEM);
return block;
}
#else
/* LUA_DEBUG */
#define MARK 55
int32 numblocks = 0;
int32 totalmem = 0;
static void *checkblock(void *block) {
int32 *b = (int32 *)block - 1;
int32 size = *b;
assert(*(((char *)b) + size + sizeof(int32)) == MARK);
numblocks--;
totalmem -= size;
return b;
}
void *luaM_realloc(void *block, int32 size) {
int32 realsize = HEADER + size + 1;
int32 realsize = sizeof(int32) + size + sizeof(char);
if (realsize != (size_t)realsize)
lua_error("Allocation Error: Block too big");
if (size == 0) { // ANSI doesn't need this, but some machines...
if (block) {
memset(block, -1, *((int32 *)block - 1)); // erase block
block = checkblock(block);
free(block);
}
return NULL;
}
if (block) {
block = checkblock(block);
block = (int32 *)realloc(block, realsize);
} else
block = (int32 *)malloc(realsize);
if (!block)
lua_error(memEM);
totalmem += size;
numblocks++;
*(int32 *)block = size;
*(((char *)block) + size + sizeof(int32)) = MARK;
return (int32 *)block+1;
}
#endif
} // end of namespace Grim

38
engines/grim/lua/lmem.h Normal file
View File

@@ -0,0 +1,38 @@
/*
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LMEM_H
#define GRIM_LMEM_H
#include "common/scummsys.h"
namespace Grim {
// memory error messages
#define codeEM "code size overflow"
#define constantEM "constant table overflow"
#define refEM "reference table overflow"
#define tableEM "table overflow"
#define memEM "not enough memory"
void *luaM_realloc (void *oldblock, int32 size);
int32 luaM_growaux (void **block, int32 nelems, int32 size, const char *errormsg, int32 limit);
#define luaM_free(b) free((b))
#define luaM_malloc(t) malloc((t))
#define luaM_new(t) ((t *)malloc(sizeof(t)))
#define luaM_newvector(n, t) ((t *)malloc((n) * sizeof(t)))
#define luaM_growvector(old, n, t, e, l) (luaM_growaux((void **)old, n, sizeof(t), e, l))
#define luaM_reallocvector(v, n, t) ((t *)realloc(v,(n) * sizeof(t)))
#ifdef LUA_DEBUG
extern int32 numblocks;
extern int32 totalmem;
#endif
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,84 @@
/*
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lstate.h"
namespace Grim {
const char *luaO_typenames[] = { // ORDER LUA_T
"userdata", "number", "string", "table", "function", "function", "task",
"nil", "function", "mark", "mark", "mark", "line", nullptr
};
TObject luaO_nilobject = { LUA_T_NIL, { nullptr } };
// hash dimensions values
static int32 dimensions[] = {
5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421,
12853, 25717, 51437, 102811, 205619, 411233, 822433,
1644817, 3289613, 6579211, 13158023, MAX_INT
};
int32 luaO_redimension(int32 oldsize) {
for (int32 i = 0; dimensions[i] < MAX_INT; i++) {
if (dimensions[i] > oldsize)
return dimensions[i];
}
lua_error("table overflow");
return 0; // to avoid warnings
}
int32 luaO_equalObj(TObject *t1, TObject *t2) {
if (ttype(t1) != ttype(t2))
return 0;
switch (ttype(t1)) {
case LUA_T_NIL:
return 1;
case LUA_T_NUMBER:
return nvalue(t1) == nvalue(t2);
case LUA_T_USERDATA:
return (t1->value.ud.id == t2->value.ud.id && t1->value.ud.tag == t2->value.ud.tag);
case LUA_T_STRING:
return tsvalue(t1) == tsvalue(t2);
case LUA_T_ARRAY:
return avalue(t1) == avalue(t2);
case LUA_T_PROTO:
return tfvalue(t1) == tfvalue(t2);
case LUA_T_CPROTO:
return fvalue(t1) == fvalue(t2);
case LUA_T_CLOSURE:
return t1->value.cl == t2->value.cl;
case LUA_T_TASK:
return nvalue(t1) == nvalue(t2);
default:
#ifdef LUA_DEBUG
LUA_INTERNALERROR("internal error in `lua_equalObj'");
#endif
return 0; // UNREACHABLE
}
}
int luaO_findstring(const char *name, const char *list[]) {
for (int i = 0; list[i]; i++)
if (strcmp(list[i], name) == 0)
return i;
return -1; // name not found
}
void luaO_insertlist(GCnode *root, GCnode *node) {
node->next = root->next;
root->next = node;
node->marked = 0;
}
} // end of namespace Grim

154
engines/grim/lua/lobject.h Normal file
View File

@@ -0,0 +1,154 @@
/*
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LOBJECT_H
#define GRIM_LOBJECT_H
#include "engines/grim/lua/lua.h"
namespace Grim {
#ifdef LUA_DEBUG
#include "engines/grim/lua/lauxlib.h"
#define LUA_INTERNALERROR(s) luaL_verror("INTERNAL ERROR - %s [%s:%d]", (s), __FILE__, __LINE__)
#define LUA_ASSERT(c, s) { if (!(c)) LUA_INTERNALERROR(s); }
#else
#define LUA_INTERNALERROR(s) // empty
#define LUA_ASSERT(c, s) // empty
#endif
#define MAX_INT (2147483647 - 2) // maximum value of an int (-2 for safety)
#define MAX_WORD (65534U)
/*
** Lua TYPES
** WARNING: if you change the order of this enumeration,
** grep "ORDER LUA_T"
*/
typedef enum {
LUA_T_USERDATA = 0, // tag default for userdata
LUA_T_NUMBER = -1, // fixed tag for numbers
LUA_T_STRING = -2, // fixed tag for strings
LUA_T_ARRAY = -3, // tag default for tables (or arrays)
LUA_T_PROTO = -4, // fixed tag for functions
LUA_T_CPROTO = -5, // fixed tag for Cfunctions
LUA_T_TASK = -6, // task tag
LUA_T_NIL = -7, // last "pre-defined" tag
LUA_T_CLOSURE = -8,
LUA_T_CLMARK = -9, // mark for closures
LUA_T_PMARK = -10, // mark for Lua prototypes
LUA_T_CMARK = -11, // mark for C prototypes
LUA_T_LINE = -12
} lua_Type;
#define NUM_TYPES 12
#define NUM_TAGS 8
typedef struct UserData {
int32 id;
int32 tag;
} UserData;
typedef union {
lua_CFunction f; // LUA_T_CPROTO, LUA_T_CMARK
float n; // LUA_T_NUMBER
struct TaggedString *ts; // LUA_T_STRING
struct TProtoFunc *tf; // LUA_T_PROTO, LUA_T_PMARK
struct Closure *cl; // LUA_T_CLOSURE, LUA_T_CLMARK
struct Hash *a; // LUA_T_ARRAY
int32 i; // LUA_T_LINE
struct UserData ud; // LUA_T_USERDATA
} Value;
typedef struct TObject {
lua_Type ttype;
Value value;
} TObject;
/*
** generic header for garbage collector lists
*/
typedef struct GCnode {
struct GCnode *next;
int32 marked;
} GCnode;
/*
** String headers for string table
*/
typedef struct TaggedString {
GCnode head;
int32 constindex; // hint to reuse constants (= -1 if this is a userdata)
uint32 hash;
TObject globalval;
char str[1]; // \0 byte already reserved
} TaggedString;
/*
** Function Prototypes
*/
typedef struct TProtoFunc {
GCnode head;
struct TObject *consts;
int32 nconsts;
byte *code; // ends with opcode ENDCODE
int32 lineDefined;
TaggedString *fileName;
struct LocVar *locvars; // ends with line = -1
} TProtoFunc;
typedef struct LocVar {
TaggedString *varname; // NULL signals end of scope
int32 line;
} LocVar;
// Macros to access structure members
#define ttype(o) ((o)->ttype)
#define nvalue(o) ((o)->value.n)
#define svalue(o) ((o)->value.ts->str)
#define tsvalue(o) ((o)->value.ts)
#define clvalue(o) ((o)->value.cl)
#define avalue(o) ((o)->value.a)
#define fvalue(o) ((o)->value.f)
#define tfvalue(o) ((o)->value.tf)
#define protovalue(o) ((o)->value.cl->consts)
/*
** Closures
*/
typedef struct Closure {
GCnode head;
int32 nelems; // not included the first one (always the prototype)
TObject consts[1]; // at least one for prototype
} Closure;
typedef struct Node {
TObject ref;
TObject val;
} Node;
typedef struct Hash {
GCnode head;
Node *node;
int32 nhash;
int32 nuse;
int32 htag;
} Hash;
extern const char *luaO_typenames[];
extern TObject luaO_nilobject;
int32 luaO_equalObj(TObject *t1, TObject *t2);
int32 luaO_redimension(int32 oldsize);
int luaO_findstring(const char *name, const char *list[]);
void luaO_insertlist(GCnode *root, GCnode *node);
#define luaO_memup(d, s, n) memmove(d, s, n)
#define luaO_memdown(d, s, n) memmove(d, s, n)
} // end of namespace Grim
#endif

180
engines/grim/lua/lopcodes.h Normal file
View File

@@ -0,0 +1,180 @@
/*
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LOPCODES_H
#define GRIM_LOPCODES_H
namespace Grim {
/*
** NOTICE: variants of the same opcode must be consecutive: First, those
** with byte parameter, then with built-in parameters, and last with
** word parameter.
*/
typedef enum {
// name parm before after side effect
//-----------------------------------------------------------------------------
ENDCODE, // - - -
PUSHNIL, // b - nil_0...nil_b
PUSHNIL0, // - - nil
PUSHNUMBER, // b - (float)b
PUSHNUMBER0, // - - 0.0
PUSHNUMBER1, // - - 1.0
PUSHNUMBER2, // - - 2.0
PUSHNUMBERW, // w - (float)w
PUSHCONSTANT, // b - CNST[b]
PUSHCONSTANT0, // - - CNST[0]
PUSHCONSTANT1, // - - CNST[1]
PUSHCONSTANT2, // - - CNST[2]
PUSHCONSTANT3, // - - CNST[3]
PUSHCONSTANT4, // - - CNST[4]
PUSHCONSTANT5, // - - CNST[5]
PUSHCONSTANT6, // - - CNST[6]
PUSHCONSTANT7, // - - CNST[7]
PUSHCONSTANTW, // w - CNST[w]
PUSHUPVALUE, // b - Closure[b]
PUSHUPVALUE0, // - - Closure[0]
PUSHUPVALUE1, // - - Closure[1]
PUSHLOCAL, // b - LOC[b]
PUSHLOCAL0, // - - LOC[0]
PUSHLOCAL1, // - - LOC[1]
PUSHLOCAL2, // - - LOC[2]
PUSHLOCAL3, // - - LOC[3]
PUSHLOCAL4, // - - LOC[4]
PUSHLOCAL5, // - - LOC[5]
PUSHLOCAL6, // - - LOC[6]
PUSHLOCAL7, // - - LOC[7]
GETGLOBAL, // b - VAR[CNST[b]]
GETGLOBAL0, // - - VAR[CNST[0]]
GETGLOBAL1, // - - VAR[CNST[1]]
GETGLOBAL2, // - - VAR[CNST[2]]
GETGLOBAL3, // - - VAR[CNST[3]]
GETGLOBAL4, // - - VAR[CNST[4]]
GETGLOBAL5, // - - VAR[CNST[5]]
GETGLOBAL6, // - - VAR[CNST[6]]
GETGLOBAL7, // - - VAR[CNST[7]]
GETGLOBALW, // w - VAR[CNST[w]]
GETTABLE, // - i t t[i]
GETDOTTED, // b t t[CNST[b]]
GETDOTTED0, // - t t[CNST[0]]
GETDOTTED1, // - t t[CNST[1]]
GETDOTTED2, // - t t[CNST[2]]
GETDOTTED3, // - t t[CNST[3]]
GETDOTTED4, // - t t[CNST[4]]
GETDOTTED5, // - t t[CNST[5]]
GETDOTTED6, // - t t[CNST[6]]
GETDOTTED7, // - t t[CNST[7]]
GETDOTTEDW, // w t t[CNST[w]]
PUSHSELF, // b t t t[CNST[b]]
PUSHSELF0, // - t t t[CNST[0]]
PUSHSELF1, // - t t t[CNST[1]]
PUSHSELF2, // - t t t[CNST[2]]
PUSHSELF3, // - t t t[CNST[3]]
PUSHSELF4, // - t t t[CNST[4]]
PUSHSELF5, // - t t t[CNST[5]]
PUSHSELF6, // - t t t[CNST[6]]
PUSHSELF7, // - t t t[CNST[7]]
PUSHSELFW, // w t t t[CNST[w]]
CREATEARRAY, // b - newarray(size = b)
CREATEARRAY0, // - - newarray(size = 0)
CREATEARRAY1, // - - newarray(size = 1)
CREATEARRAYW, // w - newarray(size = w)
SETLOCAL, // b x - LOC[b]=x
SETLOCAL0, // - x - LOC[0]=x
SETLOCAL1, // - x - LOC[1]=x
SETLOCAL2, // - x - LOC[2]=x
SETLOCAL3, // - x - LOC[3]=x
SETLOCAL4, // - x - LOC[4]=x
SETLOCAL5, // - x - LOC[5]=x
SETLOCAL6, // - x - LOC[6]=x
SETLOCAL7, // - x - LOC[7]=x
SETGLOBAL, // b x - VAR[CNST[b]]=x
SETGLOBAL0, // - x - VAR[CNST[0]]=x
SETGLOBAL1, // - x - VAR[CNST[1]]=x
SETGLOBAL2, // - x - VAR[CNST[2]]=x
SETGLOBAL3, // - x - VAR[CNST[3]]=x
SETGLOBAL4, // - x - VAR[CNST[4]]=x
SETGLOBAL5, // - x - VAR[CNST[5]]=x
SETGLOBAL6, // - x - VAR[CNST[6]]=x
SETGLOBAL7, // - x - VAR[CNST[7]]=x
SETGLOBALW, // w x - VAR[CNST[w]]=x
SETTABLE0, // - vci t - t[i]=v
SETTABLE, // b v a_b...a_1 i t a_b...a_1 i t t[i]=v
SETLIST, // b c v_c...v_1 t - t[i+b*FPF]=v_i
SETLIST0, // b v_b...v_1 t - t[i]=v_i
SETLISTW, // w c v_c...v_1 t - t[i+w*FPF]=v_i
SETMAP, // b v_b k_b ...v_0 k_0 t t t[k_i]=v_i
SETMAP0, // - v_0 k_0 t t t[k_0]=v_0
EQOP, // - y x (x==y)? 1 : nil
NEQOP, // - y x (x~=y)? 1 : nil
LTOP, // - y x (x<y)? 1 : nil
LEOP, // - y x (x<y)? 1 : nil
GTOP, // - y x (x>y)? 1 : nil
GEOP, // - y x (x>=y)? 1 : nil
ADDOP, // - y x x+y
SUBOP, // - y x x-y
MULTOP, // - y x x*y
DIVOP, // - y x x/y
POWOP, // - y x x^y
CONCOP, // - y x x..y
MINUSOP, // - x -x
NOTOP, // - x (x==nil)? 1 : nil
ONTJMP, // b x (x!=nil)? x : - (x!=nil)? PC+=b
ONTJMPW, // w x (x!=nil)? x : - (x!=nil)? PC+=w
ONFJMP, // b x (x==nil)? x : - (x==nil)? PC+=b
ONFJMPW, // w x (x==nil)? x : - (x==nil)? PC+=w
JMP, // b - - PC+=b
JMPW, // w - - PC+=w
IFFJMP, // b x - (x==nil)? PC+=b
IFFJMPW, // w x - (x==nil)? PC+=w
IFTUPJMP, // b x - (x!=nil)? PC-=b
IFTUPJMPW, // w x - (x!=nil)? PC-=w
IFFUPJMP, // b x - (x==nil)? PC-=b
IFFUPJMPW, // w x - (x==nil)? PC-=w
CLOSURE, // c f v_c...v_1 closure(f, v_c...v_1)
CLOSURE0, // - f closure(f)
CLOSURE1, // - f v closure(f, v)
CALLFUNC, // b c v_c...v_1 f r_b...r_1 f(v1,...,v_c)
CALLFUNC0, // b v_b...v_1 f - f(v1,...,v_b)
CALLFUNC1, // b v_b...v_1 f r_1 f(v1,...,v_b)
RETCODE, // b - -
SETLINE, // b - - LINE=b
SETLINEW, // w - - LINE=w
POP, // b - - TOP-=(b+1)
POP0, // - - - TOP-=1
POP1 // - - - TOP-=2
} OpCode;
#define RFIELDS_PER_FLUSH 32 // records (SETMAP)
#define LFIELDS_PER_FLUSH 64 // lists (SETLIST)
#define ZEROVARARG 64
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,21 @@
/*
** Syntax analizer and code generator
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LPARSER_H
#define GRIM_LPARSER_H
#include "lobject.h"
#include "lzio.h"
namespace Grim {
void luaY_codedebugline(int32 line);
TProtoFunc *luaY_parser(ZIO *z);
void luaY_error(const char *s);
void luaY_syntaxerror(const char *s, const char *token);
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,584 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "common/endian.h"
#include "common/debug.h"
#include "engines/grim/savegame.h"
#include "engines/grim/lua/ltask.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/ltable.h"
#include "engines/grim/lua/lvm.h"
#include "engines/grim/lua/lopcodes.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
static void restoreObjectValue(TObject *object, SaveGame *savedState) {
object->ttype = (lua_Type)savedState->readLESint32();
switch (object->ttype) {
case LUA_T_NUMBER:
case LUA_T_TASK:
{
object->value.n = savedState->readFloat();
}
break;
case LUA_T_NIL:
{
object->value.ts = nullptr;
}
break;
case LUA_T_ARRAY:
{
PointerId ptr;
ptr.id = savedState->readLEUint64();
object->value.a = (Hash *)makePointerFromId(ptr);
}
break;
case LUA_T_USERDATA:
{
object->value.ud.id = savedState->readLESint32();
object->value.ud.tag = savedState->readLESint32();
if (savedState->saveMinorVersion() == 0) {
savedState->readLEUint32();
savedState->readLEUint32();
}
}
break;
case LUA_T_STRING:
{
PointerId ptr;
ptr.id = savedState->readLEUint64();
object->value.ts = (TaggedString *)makePointerFromId(ptr);
}
break;
case LUA_T_PROTO:
case LUA_T_PMARK:
{
PointerId ptr;
ptr.id = savedState->readLEUint64();
object->value.tf = (TProtoFunc *)makePointerFromId(ptr);
}
break;
case LUA_T_CPROTO:
case LUA_T_CMARK:
{
PointerId ptr;
ptr.id = savedState->readLEUint64();
// WORKAROUND: C++ forbids casting from a pointer-to-function to a
// pointer-to-object. We use a union to work around that.
union {
void *objPtr;
lua_CFunction funcPtr;
} ptrUnion;
ptrUnion.objPtr = makePointerFromId(ptr);
object->value.f = ptrUnion.funcPtr;
}
break;
case LUA_T_CLOSURE:
case LUA_T_CLMARK:
{
PointerId ptr;
ptr.id = savedState->readLEUint64();
object->value.cl = (Closure *)makePointerFromId(ptr);
}
break;
case LUA_T_LINE:
{
object->value.i = savedState->readLESint32();
}
break;
default:
PointerId ptr;
ptr.id = savedState->readLEUint64();
object->value.ts = (TaggedString *)makePointerFromId(ptr);
}
}
struct ArrayIDObj {
void *object;
PointerId idObj;
};
static int sortCallback(const void *id1, const void *id2) {
if (((const ArrayIDObj *)id1)->idObj.id > ((const ArrayIDObj *)id2)->idObj.id) {
return 1;
} else if (((const ArrayIDObj *)id1)->idObj.id < ((const ArrayIDObj *)id2)->idObj.id) {
return -1;
} else {
return 0;
}
}
int32 arrayHashTablesCount = 0;
int32 arrayProtoFuncsCount = 0;
int32 arrayClosuresCount = 0;
int32 arrayStringsCount = 0;
ArrayIDObj *arrayStrings = nullptr;
ArrayIDObj *arrayHashTables = nullptr;
ArrayIDObj *arrayClosures = nullptr;
ArrayIDObj *arrayProtoFuncs = nullptr;
static bool arraysAllreadySort = false;
static void recreateObj(TObject *obj) {
if (obj->ttype == LUA_T_CPROTO) {
uintptr id = ((uintptr)(obj->value.f)) >> 16;
luaL_libList *list = list_of_libs;
while (list) {
if (id == 0)
break;
id--;
list = list->next;
}
int32 numberFunc = (uintptr)(obj->value.f) & 0xffff;
if (list && id == 0 && numberFunc < list->number) {
obj->value.f = list->list[numberFunc].func;
} else {
obj->value.f = nullptr;
assert(obj->value.f);
}
} else if (obj->ttype == LUA_T_NIL || obj->ttype == LUA_T_LINE || obj->ttype == LUA_T_NUMBER ||
obj->ttype == LUA_T_TASK || obj->ttype == LUA_T_USERDATA) {
return;
} else {
if (obj->value.i == 0)
return;
if (!arraysAllreadySort) {
arraysAllreadySort = true;
qsort(arrayHashTables, arrayHashTablesCount, sizeof(ArrayIDObj), sortCallback);
qsort(arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
qsort(arrayClosures, arrayClosuresCount, sizeof(ArrayIDObj), sortCallback);
qsort(arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
}
ArrayIDObj *found;
ArrayIDObj tmpId;
tmpId.object = nullptr;
switch (obj->ttype) {
case LUA_T_PMARK:
tmpId.idObj = makeIdFromPointer(obj->value.tf);
found = (ArrayIDObj *)bsearch(&tmpId, arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.tf = (TProtoFunc *)found->object;
break;
case LUA_T_PROTO:
tmpId.idObj = makeIdFromPointer(obj->value.tf);
found = (ArrayIDObj *)bsearch(&tmpId, arrayProtoFuncs, arrayProtoFuncsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.tf = (TProtoFunc *)found->object;
break;
case LUA_T_CLOSURE:
tmpId.idObj = makeIdFromPointer(obj->value.cl);
found = (ArrayIDObj *)bsearch(&tmpId, arrayClosures, arrayClosuresCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.cl = (Closure *)found->object;
break;
case LUA_T_ARRAY:
tmpId.idObj = makeIdFromPointer(obj->value.a);
found = (ArrayIDObj *)bsearch(&tmpId, arrayHashTables, arrayHashTablesCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.a = (Hash *)found->object;
break;
case LUA_T_STRING:
tmpId.idObj = makeIdFromPointer(obj->value.ts);
found = (ArrayIDObj *)bsearch(&tmpId, arrayStrings, arrayStringsCount, sizeof(ArrayIDObj), sortCallback);
assert(found);
obj->value.ts = (TaggedString *)found->object;
break;
default:
obj->value.i = 0;
obj->value.ts = nullptr;
return;
}
}
}
void lua_Restore(SaveGame *savedState) {
savedState->beginSection('LUAS');
lua_close();
lua_rootState = lua_state = luaM_new(LState);
lua_stateinit(lua_state);
lua_resetglobals();
arrayStringsCount = savedState->readLESint32();
arrayClosuresCount = savedState->readLESint32();
arrayHashTablesCount = savedState->readLESint32();
arrayProtoFuncsCount = savedState->readLESint32();
int32 rootGlobalCount = savedState->readLESint32();
arrayStrings = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayStringsCount);
ArrayIDObj *arraysObj = arrayStrings;
int32 maxStringsLength;
maxStringsLength = savedState->readLESint32();
char *tempStringBuffer = (char *)luaM_malloc(maxStringsLength + 1); // add extra char for 0 terminate string
//printf("1: %d\n", g_grim->_savedState->getBufferPos());
int32 i;
for (i = 0; i < arrayStringsCount; i++) {
arraysObj->idObj.id = savedState->readLEUint64();
int32 constIndex = savedState->readLESint32();
TaggedString *tempString = nullptr;
if (constIndex != -1) {
TObject obj;
restoreObjectValue(&obj, savedState);
int32 length = savedState->readLESint32();
savedState->read(tempStringBuffer, length);
tempStringBuffer[length] = '\0';
tempString = luaS_new(tempStringBuffer);
tempString->globalval = obj;
}
assert(tempString);
tempString->constindex = constIndex;
arraysObj->object = tempString;
arraysObj++;
}
luaM_free(tempStringBuffer);
//printf("2: %d\n", g_grim->_savedState->getBufferPos());
int32 l;
Closure *tempClosure;
GCnode *prevClosure = &rootcl;
arraysObj = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayClosuresCount);
arrayClosures = arraysObj;
for (i = 0; i < arrayClosuresCount; i++) {
arraysObj->idObj.id = savedState->readLEUint64();
int32 countElements = savedState->readLESint32();
tempClosure = (Closure *)luaM_malloc((countElements * sizeof(TObject)) + sizeof(Closure));
luaO_insertlist(prevClosure, (GCnode *)tempClosure);
prevClosure = (GCnode *)tempClosure;
tempClosure->nelems = countElements;
for (l = 0; l <= tempClosure->nelems; l++) {
restoreObjectValue(&tempClosure->consts[l], savedState);
}
arraysObj->object = tempClosure;
arraysObj++;
}
Hash *tempHash;
GCnode *prevHash = &roottable;
arraysObj = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayHashTablesCount);
arrayHashTables = arraysObj;
for (i = 0; i < arrayHashTablesCount; i++) {
arraysObj->idObj.id = savedState->readLEUint64();
tempHash = luaM_new(Hash);
tempHash->nhash = savedState->readLESint32();
tempHash->nuse = savedState->readLESint32();
tempHash->htag = savedState->readLESint32();
tempHash->node = hashnodecreate(tempHash->nhash);
luaO_insertlist(prevHash, (GCnode *)tempHash);
prevHash = (GCnode *)tempHash;
for (l = 0; l < tempHash->nuse; l++) {
restoreObjectValue(&tempHash->node[l].ref, savedState);
restoreObjectValue(&tempHash->node[l].val, savedState);
}
arraysObj->object = tempHash;
arraysObj++;
}
TProtoFunc *tempProtoFunc;
GCnode *oldProto = &rootproto;
arrayProtoFuncs = (ArrayIDObj *)luaM_malloc(sizeof(ArrayIDObj) * arrayProtoFuncsCount);
arraysObj = arrayProtoFuncs;
for (i = 0; i < arrayProtoFuncsCount; i++) {
arraysObj->idObj.id = savedState->readLEUint64();
tempProtoFunc = luaM_new(TProtoFunc);
luaO_insertlist(oldProto, (GCnode *)tempProtoFunc);
oldProto = (GCnode *)tempProtoFunc;
PointerId ptr;
ptr.id = savedState->readLEUint64();
tempProtoFunc->fileName = (TaggedString *)makePointerFromId(ptr);
tempProtoFunc->lineDefined = savedState->readLESint32();
tempProtoFunc->nconsts = savedState->readLESint32();
if (tempProtoFunc->nconsts > 0) {
tempProtoFunc->consts = (TObject *)luaM_malloc(tempProtoFunc->nconsts * sizeof(TObject));
} else {
tempProtoFunc->consts = nullptr;
}
for (l = 0; l < tempProtoFunc->nconsts; l++) {
restoreObjectValue(&tempProtoFunc->consts[l], savedState);
}
int32 countVariables = savedState->readLESint32();
if (countVariables) {
tempProtoFunc->locvars = (LocVar *)luaM_malloc(countVariables * sizeof(LocVar));
} else {
tempProtoFunc->locvars = nullptr;
}
for (l = 0; l < countVariables; l++) {
ptr.id = savedState->readLEUint64();
tempProtoFunc->locvars[l].varname = (TaggedString *)makePointerFromId(ptr);
tempProtoFunc->locvars[l].line = savedState->readLESint32();
}
int32 codeSize = savedState->readLESint32();
tempProtoFunc->code = (byte *)luaM_malloc(codeSize);
savedState->read(tempProtoFunc->code, codeSize);
arraysObj->object = tempProtoFunc;
arraysObj++;
}
for (i = 0; i < NUM_HASHS; i++) {
stringtable *tempStringTable = &string_root[i];
for (l = 0; l < tempStringTable->size; l++) {
TaggedString *tempString = tempStringTable->hash[l];
if (tempString && tempString->constindex != -1 && tempString != &EMPTY) {
recreateObj(&tempString->globalval);
}
}
}
tempProtoFunc = (TProtoFunc *)rootproto.next;
while (tempProtoFunc) {
TObject tempObj;
tempObj.value.ts = (TaggedString *)tempProtoFunc->fileName;
tempObj.ttype = LUA_T_STRING;
recreateObj(&tempObj);
tempProtoFunc->fileName = (TaggedString *)tempObj.value.ts;
for (i = 0; i < tempProtoFunc->nconsts; i++) {
recreateObj(&tempProtoFunc->consts[i]);
}
if (tempProtoFunc->locvars) {
for (i = 0; tempProtoFunc->locvars[i].line != -1; i++) {
TObject tempObj2;
tempObj2.value.ts = tempProtoFunc->locvars[i].varname;
tempObj2.ttype = LUA_T_STRING;
recreateObj(&tempObj2);
tempProtoFunc->locvars[i].varname = (TaggedString *)tempObj2.value.ts;
}
}
tempProtoFunc = (TProtoFunc *)tempProtoFunc->head.next;
}
tempHash = (Hash *)roottable.next;
while (tempHash) {
for (i = 0; i < tempHash->nuse; i++) {
recreateObj(&tempHash->node[i].ref);
recreateObj(&tempHash->node[i].val);
}
Node *oldNode = tempHash->node;
tempHash->node = hashnodecreate(tempHash->nhash);
for (i = 0; i < tempHash->nuse; i++) {
Node *newNode = oldNode + i;
if (newNode->ref.ttype != LUA_T_NIL && newNode->val.ttype != LUA_T_NIL) {
*node(tempHash, present(tempHash, &newNode->ref)) = *newNode;
}
}
luaM_free(oldNode);
tempHash = (Hash *)tempHash->head.next;
}
tempClosure = (Closure *)rootcl.next;
while (tempClosure) {
for (i = 0; i <= tempClosure->nelems; i++) {
recreateObj(&tempClosure->consts[i]);
}
tempClosure = (Closure *)tempClosure->head.next;
}
TaggedString *tempListString = (TaggedString *)&(rootglobal);
for (i = 0; i < rootGlobalCount; i++) {
TObject tempObj;
TaggedString *tempString = nullptr;
tempObj.ttype = LUA_T_STRING;
PointerId ptr;
ptr.id = savedState->readLEUint64();
tempObj.value.ts = (TaggedString *)makePointerFromId(ptr);
recreateObj(&tempObj);
tempString = (TaggedString *)tempObj.value.ts;
assert(tempString);
tempListString->head.next = (GCnode *)tempString;
tempListString = tempString;
}
tempListString->head.next = nullptr;
restoreObjectValue(&errorim, savedState);
recreateObj(&errorim);
IMtable_size = savedState->readLESint32();
if (IMtable_size > 0) {
IMtable = (IM *)luaM_malloc(IMtable_size * sizeof(IM));
for (i = 0; i < IMtable_size; i++) {
IM *im = &IMtable[i];
for (l = 0; l < IM_N; l++) {
restoreObjectValue(&im->int_method[l], savedState);
recreateObj(&im->int_method[l]);
}
}
} else {
IMtable = nullptr;
}
last_tag = savedState->readLESint32();
refSize = savedState->readLESint32();
if (refSize > 0) {
refArray = (ref *)luaM_malloc(refSize * sizeof(ref));
for (i = 0; i < refSize; i++) {
restoreObjectValue(&refArray[i].o, savedState);
recreateObj(&refArray[i].o);
refArray[i].status = (Status)savedState->readLESint32();
}
} else {
refArray = nullptr;
}
GCthreshold = savedState->readLESint32();
nblocks = savedState->readLESint32();
Mbuffsize = savedState->readLESint32();
Mbuffer = (char *)luaM_malloc(Mbuffsize);
savedState->read(Mbuffer, Mbuffsize);
int32 MbaseOffset = savedState->readLESint32();
Mbuffbase = MbaseOffset + Mbuffer;
Mbuffnext = savedState->readLESint32();
globalTaskSerialId = savedState->readLESint32();
int32 countStates = savedState->readLESint32();
int32 currentState = savedState->readLESint32();
LState *state = lua_rootState;
for (l = 0; l < countStates; l++) {
if (l == 0)
state = lua_rootState;
else {
LState *s = luaM_new(LState);
lua_stateinit(s);
state->next = s;
s->prev = state;
state = s;
}
int32 countTasks = savedState->readLESint32();
if (countTasks) {
lua_Task *task = nullptr;
for (i = 0; i < countTasks; i++) {
if (i == 0) {
task = state->task = luaM_new(lua_Task);
lua_taskinit(task, nullptr, 0, 0);
} else {
lua_Task *t = luaM_new(lua_Task);
lua_taskinit(t, nullptr, 0, 0);
task->next = t;
task = t;
}
task->S = &state->stack;
TObject tempObj;
tempObj.ttype = LUA_T_CLOSURE;
PointerId ptr;
ptr.id = savedState->readLEUint64();
tempObj.value.cl = (Closure *)makePointerFromId(ptr);
recreateObj(&tempObj);
task->cl = (Closure *)tempObj.value.cl;
tempObj.ttype = LUA_T_PROTO;
ptr.id = savedState->readLEUint64();
tempObj.value.tf = (TProtoFunc *)makePointerFromId(ptr);
recreateObj(&tempObj);
task->tf = (TProtoFunc *)tempObj.value.tf;
task->base = savedState->readLESint32();
task->initBase = savedState->readLESint32();
task->initResults = savedState->readLESint32();
task->executed = savedState->readBool();
int32 pcOffset = savedState->readLESint32();
task->pc = task->tf->code + pcOffset;
task->aux = savedState->readLESint32();
task->consts = task->tf->consts;
}
} else {
state->task = nullptr;
}
int32 n = savedState->readLESint32();
if (n < 0) {
state->prevTask = nullptr;
} else {
state->prevTask = state->task;
for (; n; n--)
state->prevTask = state->prevTask->next;
}
state->updated = savedState->readBool();
byte pauseState = savedState->readByte();
state->all_paused = pauseState & LUA_SG_ALL_PAUSED;
state->paused = (pauseState & LUA_SG_PAUSED) ? true : false;
state->preventBreakCounter = savedState->readLESint32();
state->callLevelCounter = savedState->readLESint32();
int32 stackLastSize = savedState->readLESint32();
if (state->stack.stack)
luaM_free(state->stack.stack);
state->stack.stack = (TObject *)luaM_malloc(stackLastSize * sizeof(TObject));
state->stack.last = state->stack.stack + stackLastSize - 1;
int32 stackTopSize = savedState->readLESint32();
state->stack.top = state->stack.stack + stackTopSize;
for (i = 0; i < stackTopSize; i++) {
restoreObjectValue(&state->stack.stack[i], savedState);
recreateObj(&state->stack.stack[i]);
}
state->Cstack.base = savedState->readLESint32();
state->Cstack.lua2C = savedState->readLESint32();
state->Cstack.num = savedState->readLESint32();
state->numCblocks = savedState->readLESint32();
for (i = 0; i < state->numCblocks; i++) {
state->Cblocks[i].base = savedState->readLESint32();
state->Cblocks[i].lua2C = savedState->readLESint32();
state->Cblocks[i].num = savedState->readLESint32();
}
if (savedState->saveMinorVersion() >= 3) {
state->sleepFor = savedState->readLEUint32();
}
state->id = savedState->readLEUint32();
restoreObjectValue(&state->taskFunc, savedState);
if (state->taskFunc.ttype == LUA_T_PROTO || state->taskFunc.ttype == LUA_T_CPROTO)
recreateObj(&state->taskFunc);
}
for (; currentState; currentState--)
lua_state = lua_state->next;
arraysAllreadySort = false;
arrayStringsCount = 0;
arrayHashTablesCount = 0;
arrayClosuresCount = 0;
arrayProtoFuncsCount = 0;
luaM_free(arrayClosures);
luaM_free(arrayStrings);
luaM_free(arrayHashTables);
luaM_free(arrayProtoFuncs);
arrayHashTables = nullptr;
arrayClosures = nullptr;
arrayProtoFuncs = nullptr;
arrayStrings = nullptr;
savedState->endSection();
}
} // end of namespace Grim

386
engines/grim/lua/lsave.cpp Normal file
View File

@@ -0,0 +1,386 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "common/endian.h"
#include "common/debug.h"
#include "engines/grim/savegame.h"
#include "engines/grim/lua/ltask.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/ltm.h"
#include "engines/grim/lua/ltable.h"
#include "engines/grim/lua/lvm.h"
#include "engines/grim/lua/lopcodes.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
PointerId makeIdFromPointer(void *ptr) {
PointerId pointer;
pointer.id = (uintptr)ptr;
return pointer;
}
void *makePointerFromId(PointerId ptr) {
return (void *)ptr.id;
}
static void saveObjectValue(TObject *object, SaveGame *savedState) {
savedState->writeLESint32(object->ttype);
switch (object->ttype) {
case LUA_T_CPROTO:
case LUA_T_CMARK:
{
luaL_libList *list = list_of_libs;
int32 idObj = 0;
while (list) {
for (int32 l = 0; l < list->number; l++) {
if (list->list[l].func == object->value.f) {
idObj = (idObj << 16) | l;
savedState->writeLESint32(idObj);
savedState->writeLESint32(0);
return;
}
}
list = list->next;
idObj++;
}
assert(0);
break;
}
case LUA_T_NUMBER:
case LUA_T_TASK:
{
savedState->writeFloat(object->value.n);
}
break;
case LUA_T_NIL:
break;
case LUA_T_ARRAY:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.a).id);
}
break;
case LUA_T_USERDATA:
{
savedState->writeLESint32(object->value.ud.id);
savedState->writeLESint32(object->value.ud.tag);
}
break;
case LUA_T_STRING:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.ts).id);
}
break;
case LUA_T_PROTO:
case LUA_T_PMARK:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.tf).id);
}
break;
case LUA_T_CLOSURE:
case LUA_T_CLMARK:
{
savedState->writeLEUint64(makeIdFromPointer(object->value.cl).id);
}
break;
case LUA_T_LINE:
{
savedState->writeLESint32(object->value.i);
}
break;
default:
savedState->writeLEUint64(makeIdFromPointer(object->value.ts).id);
}
}
static int32 opcodeSizeTable[] = {
1, 2, 1, 2, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1,
3, 2, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
1, 1, 1, 3, 1, 2, 3, 2, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1, 1,
3, 2, 2, 2, 2, 3, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 3, 2, 1, 1,
1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3,
2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 3, 2, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 3, 2, 4, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 1, 1, 3, 2, 2, 2, 2, 3, 2, 1, 1
};
void lua_Save(SaveGame *savedState) {
savedState->beginSection('LUAS');
lua_collectgarbage(0);
int32 i, l;
int32 countElements = 0;
int32 maxStringLength = 0;
// Check for max length for strings and count them
for (i = 0; i < NUM_HASHS; i++) {
stringtable *tempStringTable = &string_root[i];
for (l = 0; l < tempStringTable->size; l++) {
if (tempStringTable->hash[l] && tempStringTable->hash[l] != &EMPTY) {
countElements++;
if (tempStringTable->hash[l]->constindex != -1) {
int len = strlen(tempStringTable->hash[l]->str);
if (maxStringLength < len) {
maxStringLength = len;
}
}
}
}
}
// save number of strings
savedState->writeLESint32(countElements);
// save number of closures
countElements = 0;
GCnode *tempNode;
tempNode = rootcl.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save number of tables
countElements = 0;
tempNode = roottable.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save number of prototypes
countElements = 0;
tempNode = rootproto.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save number of global strings
countElements = 0;
tempNode = rootglobal.next;
while (tempNode) {
countElements++;
tempNode = tempNode->next;
}
savedState->writeLESint32(countElements);
// save maximum length for string
savedState->writeLESint32(maxStringLength);
//printf("1: %d\n", g_grim->_savedState->getBufferPos());
// save hash tables for strings and user data
TaggedString *tempString;
for (i = 0; i < NUM_HASHS; i++) {
stringtable *tempStringTable = &string_root[i];
for (l = 0; l < tempStringTable->size; l++) {
if (tempStringTable->hash[l] && tempStringTable->hash[l] != &EMPTY) {
tempString = tempStringTable->hash[l];
savedState->writeLEUint64(makeIdFromPointer(tempString).id);
savedState->writeLESint32(tempString->constindex);
if (tempString->constindex != -1) {
saveObjectValue(&tempString->globalval, savedState);
int len = strlen(tempString->str);
savedState->writeLESint32(len);
savedState->write(tempString->str, len);
}
}
}
}
//printf("2: %d\n", g_grim->_savedState->getBufferPos());
Closure *tempClosure = (Closure *)rootcl.next;
while (tempClosure) {
savedState->writeLEUint64(makeIdFromPointer(tempClosure).id);
savedState->writeLESint32(tempClosure->nelems);
for (i = 0; i <= tempClosure->nelems; i++) {
saveObjectValue(&tempClosure->consts[i], savedState);
}
tempClosure = (Closure *)tempClosure->head.next;
}
Hash *tempHash = (Hash *)roottable.next;
while (tempHash) {
savedState->writeLEUint64(makeIdFromPointer(tempHash).id);
savedState->writeLESint32(tempHash->nhash);
int32 countUsedHash = 0;
for (i = 0; i < tempHash->nhash; i++) {
Node *newNode = &tempHash->node[i];
if (newNode->ref.ttype != LUA_T_NIL && newNode->val.ttype != LUA_T_NIL) {
countUsedHash++;
}
}
savedState->writeLESint32(countUsedHash);
savedState->writeLESint32(tempHash->htag);
for (i = 0; i < tempHash->nhash; i++) {
Node *newNode = &tempHash->node[i];
if (newNode->ref.ttype != LUA_T_NIL && newNode->val.ttype != LUA_T_NIL) {
saveObjectValue(&tempHash->node[i].ref, savedState);
saveObjectValue(&tempHash->node[i].val, savedState);
}
}
tempHash = (Hash *)tempHash->head.next;
}
TProtoFunc *tempProtoFunc = (TProtoFunc *)rootproto.next;
while (tempProtoFunc) {
savedState->writeLEUint64(makeIdFromPointer(tempProtoFunc).id);
savedState->writeLEUint64(makeIdFromPointer(tempProtoFunc->fileName).id);
savedState->writeLESint32(tempProtoFunc->lineDefined);
savedState->writeLESint32(tempProtoFunc->nconsts);
for (i = 0; i < tempProtoFunc->nconsts; i++) {
saveObjectValue(&tempProtoFunc->consts[i], savedState);
}
int32 countVariables = 0;
if (tempProtoFunc->locvars) {
for (; tempProtoFunc->locvars[countVariables++].line != -1;) { }
}
savedState->writeLESint32(countVariables);
for (i = 0; i < countVariables; i++) {
savedState->writeLEUint64(makeIdFromPointer(tempProtoFunc->locvars[i].varname).id);
savedState->writeLESint32(tempProtoFunc->locvars[i].line);
}
byte *codePtr = tempProtoFunc->code + 2;
byte *tmpPtr = codePtr;
int32 opcodeId;
do {
opcodeId = *tmpPtr;
tmpPtr += opcodeSizeTable[opcodeId];
} while (opcodeId != ENDCODE);
int32 codeSize = (tmpPtr - codePtr) + 2;
savedState->writeLESint32(codeSize);
savedState->write(tempProtoFunc->code, codeSize);
tempProtoFunc = (TProtoFunc *)tempProtoFunc->head.next;
}
tempString = (TaggedString *)rootglobal.next;
while (tempString) {
savedState->writeLEUint64(makeIdFromPointer(tempString).id);
tempString = (TaggedString *)tempString->head.next;
}
saveObjectValue(&errorim, savedState);
IM *tempIm = IMtable;
savedState->writeLESint32(IMtable_size);
for (i = 0; i < IMtable_size; i++) {
for (l = 0; l < IM_N; l++) {
saveObjectValue(&tempIm->int_method[l], savedState);
}
tempIm++;
}
savedState->writeLESint32(last_tag);
savedState->writeLESint32(refSize);
for (i = 0 ; i < refSize; i++) {
saveObjectValue(&refArray[i].o, savedState);
savedState->writeLESint32(refArray[i].status);
}
savedState->writeLESint32(GCthreshold);
savedState->writeLESint32(nblocks);
savedState->writeLESint32(Mbuffsize);
savedState->write(Mbuffer, Mbuffsize);
int32 MbaseOffset = Mbuffbase - Mbuffer;
savedState->writeLESint32(MbaseOffset);
savedState->writeLESint32(Mbuffnext);
savedState->writeLESint32(globalTaskSerialId);
int32 countStates = 0, currentState = 0;
LState *state = lua_rootState;
while (state) {
if (lua_state == state)
currentState = countStates;
countStates++;
state = state->next;
}
savedState->writeLESint32(countStates);
savedState->writeLESint32(currentState);
state = lua_rootState;
while (state) {
lua_Task *task = state->task;
int32 countTasks = 0, n = -1;
while (task) {
if (state->prevTask && state->prevTask == task)
n = countTasks;
countTasks++;
task = task->next;
}
savedState->writeLESint32(countTasks);
task = state->task;
while (task) {
savedState->writeLEUint64(makeIdFromPointer(task->cl).id);
savedState->writeLEUint64(makeIdFromPointer(task->tf).id);
savedState->writeLESint32(task->base);
savedState->writeLESint32(task->initBase);
savedState->writeLESint32(task->initResults);
savedState->writeBool(task->executed);
int32 pcOffset = task->pc - task->tf->code;
savedState->writeLESint32(pcOffset);
savedState->writeLESint32(task->aux);
task = task->next;
}
savedState->writeLESint32(n);
savedState->writeBool(state->updated);
byte pauseState = 0;
pauseState = state->all_paused & LUA_SG_ALL_PAUSED;
pauseState |= state->paused ? LUA_SG_PAUSED : 0;
savedState->writeByte(pauseState);
savedState->writeLESint32(state->preventBreakCounter);
savedState->writeLESint32(state->callLevelCounter);
int32 stackLastSize = (state->stack.last - state->stack.stack) + 1;
savedState->writeLESint32(stackLastSize);
int32 stackTopSize = state->stack.top - state->stack.stack;
savedState->writeLESint32(stackTopSize);
for (i = 0; i < stackTopSize; i++) {
saveObjectValue(&state->stack.stack[i], savedState);
}
savedState->writeLESint32(state->Cstack.base);
savedState->writeLESint32(state->Cstack.lua2C);
savedState->writeLESint32(state->Cstack.num);
savedState->writeLESint32(state->numCblocks);
for (i = 0; i < state->numCblocks; i++) {
savedState->writeLESint32(state->Cblocks[i].base);
savedState->writeLESint32(state->Cblocks[i].lua2C);
savedState->writeLESint32(state->Cblocks[i].num);
}
savedState->writeLEUint32(state->sleepFor);
savedState->writeLEUint32(state->id);
saveObjectValue(&state->taskFunc, savedState);
state = state->next;
}
savedState->endSection();
}
} // end of namespace Grim

258
engines/grim/lua/lstate.cpp Normal file
View File

@@ -0,0 +1,258 @@
/*
** 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, "<actor \"%s\">", 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, "<color #%02x%02x%02x>", c.getRed(), c.getGreen(), c.getBlue());
} else
fprintf(output, "<userdata %d>", lua_getuserdata(lua_getparam(i)));
} else if (lua_isfunction(lua_getparam(i))) {
lua_getobjname(lua_getparam(i), &name);
fprintf(output, "<function %s>", 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, "<unknown>");
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

121
engines/grim/lua/lstate.h Normal file
View File

@@ -0,0 +1,121 @@
/*
** Global State
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LSTATE_H
#define GRIM_LSTATE_H
#include "engines/grim/lua/lobject.h"
#include <setjmp.h>
namespace Grim {
#define MAX_C_BLOCKS 10
#define GARBAGE_BLOCK 150
/* The pause status for the scripts is stored in one byte in the savegame.
*
* The "single script pause" status will be stored in the highest significant bit.
* For GRIM that flag is never set because GRIM does not pause single scripts.
*
* The "all scripts pause" status is a number which counts, how often
* pause_scripts(TRUE) was called without a corresponding unpause_scripts() call.
* The value is stored in the lower 7 bit of the pause status byte.
* For GRIM, since the (un)pause_scripts() are called symmetrically, only
* the lowest bit will be used.
*/
#define LUA_SG_ALL_PAUSED 0x7f
#define LUA_SG_PAUSED 0x80
typedef int32 StkId; /* index to stack elements */
struct Stack {
TObject *top;
TObject *stack;
TObject *last;
};
struct C_Lua_Stack {
StkId base; // when Lua calls C or C calls Lua, points to
// the first slot after the last parameter.
StkId lua2C; // points to first element of "array" lua2C
int32 num; // size of "array" lua2C
};
typedef struct {
int32 size;
int32 nuse; // number of elements (including EMPTYs)
TaggedString **hash;
} stringtable;
enum Status { LOCK, HOLD, FREE, COLLECTED };
struct ref {
TObject o;
enum Status status;
};
struct CallInfo {
Closure *c;
TProtoFunc *tf; // Set to NULL for C function
StkId base;
byte *pc;
int32 nResults;
};
struct lua_Task;
extern GCnode rootproto;
extern GCnode rootcl;
extern GCnode rootglobal;
extern GCnode roottable;
extern struct ref *refArray;
extern int32 refSize;
extern int32 GCthreshold;
extern int32 nblocks;
extern int32 Mbuffsize;
extern int32 Mbuffnext;
extern char *Mbuffbase;
extern char *Mbuffer;
extern TObject errorim;
extern stringtable *string_root;
extern int32 last_tag;
extern struct IM *IMtable;
extern int32 IMtable_size;
struct LState {
LState *prev; // handle to previous state in list
LState *next; // handle to next state in list
int all_paused; // counter of often pause_scripts(TRUE) was called
bool paused; // true if this particular script has been paused
int32 preventBreakCounter;
int32 callLevelCounter;
bool updated;
Stack stack; // Lua stack
C_Lua_Stack Cstack; // C2lua struct
struct FuncState *mainState, *currState; // point to local structs in yacc
struct LexState *lexstate; // point to local struct in yacc
jmp_buf *errorJmp; // current error recover point
lua_Task *task; // handle to task
lua_Task *prevTask;
uint32 id; // current id of task
TObject taskFunc;
struct C_Lua_Stack Cblocks[MAX_C_BLOCKS];
int numCblocks; // number of nested Cblocks
int sleepFor;
};
extern LState *lua_state, *lua_rootState;
extern int globalTaskSerialId;
void lua_stateinit(LState *state);
void lua_statedeinit(LState *state);
void lua_resetglobals();
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,231 @@
/*
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
#include "common/util.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
#define gcsizestring(l) (1 + (l / 64)) // "weight" for a string with length 'l'
TaggedString EMPTY = {{nullptr, 2}, 0, 0L, {LUA_T_NIL, {nullptr}}, {0}};
void luaS_init() {
int32 i;
string_root = luaM_newvector(NUM_HASHS, stringtable);
for (i = 0; i < NUM_HASHS; i++) {
string_root[i].size = 0;
string_root[i].nuse = 0;
string_root[i].hash = nullptr;
}
}
static uint32 hash(const char *s, int32 tag) {
uint32 h;
if (tag != LUA_T_STRING) {
h = (uintptr)s;
} else {
h = 0;
while (*s)
h = ((h << 5) - h) ^ (byte)*(s++);
}
return h;
}
static void grow(stringtable *tb) {
int newsize = luaO_redimension(tb->size);
TaggedString **newhash = luaM_newvector(newsize, TaggedString *);
int32 i;
for (i = 0; i < newsize; i++)
newhash[i] = nullptr;
// rehash
tb->nuse = 0;
for (i = 0; i < tb->size; i++) {
if (tb->hash[i] && tb->hash[i] != &EMPTY) {
int32 h = tb->hash[i]->hash % newsize;
while (newhash[h])
h = (h + 1) % newsize;
newhash[h] = tb->hash[i];
tb->nuse++;
}
}
luaM_free(tb->hash);
tb->size = newsize;
tb->hash = newhash;
}
static TaggedString *newone(const char *buff, int32 tag, uint32 h) {
TaggedString *ts;
if (tag == LUA_T_STRING) {
int l = strlen(buff);
ts = (TaggedString *)luaM_malloc(sizeof(TaggedString) + l);
strcpy(ts->str, buff);
ts->globalval.ttype = LUA_T_NIL; /* initialize global value */
ts->constindex = 0;
nblocks += gcsizestring(l);
} else {
ts = (TaggedString *)luaM_malloc(sizeof(TaggedString));
ts->globalval.value.ts = (TaggedString *)const_cast<char *>(buff);
ts->globalval.ttype = (lua_Type)(tag == LUA_ANYTAG ? 0 : tag);
ts->constindex = -1; /* tag -> this is a userdata */
nblocks++;
}
ts->head.marked = 0;
ts->head.next = (GCnode *)ts; // signal it is in no list
ts->hash = h;
return ts;
}
static TaggedString *insert(const char *buff, int32 tag, stringtable *tb) {
TaggedString *ts;
uint32 h = hash(buff, tag);
int32 size = tb->size;
int32 i;
int32 j = -1;
if (tb->nuse * 3 >= size * 2) {
grow(tb);
size = tb->size;
}
for (i = h % size; (ts = tb->hash[i]) != nullptr; ) {
if (ts == &EMPTY)
j = i;
else if ((ts->constindex >= 0) ? // is a string?
(tag == LUA_T_STRING && (strcmp(buff, ts->str) == 0)) :
((tag == ts->globalval.ttype || tag == LUA_ANYTAG) && buff == (const char *)ts->globalval.value.ts))
return ts;
if (++i == size)
i = 0;
}
// not found
if (j != -1) // is there an EMPTY space?
i = j;
else
tb->nuse++;
ts = tb->hash[i] = newone(buff, tag, h);
return ts;
}
TaggedString *luaS_createudata(void *udata, int32 tag) {
return insert((char *)udata, tag, &string_root[(uintptr)udata % NUM_HASHS]);
}
TaggedString *luaS_new(const char *str) {
return insert(str, LUA_T_STRING, &string_root[(uintptr)str[0] % NUM_HASHS]);
}
TaggedString *luaS_newfixedstring(const char *str) {
TaggedString *ts = luaS_new(str);
if (ts->head.marked == 0)
ts->head.marked = 2; // avoid GC
return ts;
}
void luaS_free(TaggedString *l) {
while (l) {
TaggedString *next = (TaggedString *)l->head.next;
nblocks -= (l->constindex == -1) ? 1 : gcsizestring(strlen(l->str));
luaM_free(l);
l = next;
}
}
/*
** Garbage collection functions.
*/
static void remove_from_list(GCnode *l) {
while (l) {
GCnode *next = l->next;
while (next && !next->marked)
next = l->next = next->next;
l = next;
}
}
TaggedString *luaS_collector() {
TaggedString *frees = nullptr;
remove_from_list(&rootglobal);
for (int32 i = 0; i < NUM_HASHS; i++) {
stringtable *tb = &string_root[i];
for (int32 j = 0; j < tb->size; j++) {
TaggedString *t = tb->hash[j];
if (!t)
continue;
if (t->head.marked == 1)
t->head.marked = 0;
else if (!t->head.marked) {
t->head.next = (GCnode *)frees;
frees = t;
tb->hash[j] = &EMPTY;
}
}
}
return frees;
}
TaggedString *luaS_collectudata() {
TaggedString *frees = nullptr;
rootglobal.next = nullptr; // empty list of globals
for (int32 i = 0; i < NUM_HASHS; i++) {
stringtable *tb = &string_root[i];
for (int32 j = 0; j < tb->size; j++) {
TaggedString *t = tb->hash[j];
if (!t || t == &EMPTY || t->constindex != -1)
continue; // get only user data
t->head.next = (GCnode *)frees;
frees = t;
tb->hash[j] = &EMPTY;
}
}
return frees;
}
void luaS_freeall() {
for (int32 i = 0; i < NUM_HASHS; i++) {
stringtable *tb = &string_root[i];
int32 j;
for (j = 0; j < tb->size; j++) {
TaggedString *t = tb->hash[j];
if (t == &EMPTY)
continue;
luaM_free(t);
}
luaM_free(tb->hash);
}
luaM_free(string_root);
}
void luaS_rawsetglobal(TaggedString *ts, TObject *newval) {
ts->globalval = *newval;
if (ts->head.next == (GCnode *)ts) { // is not in list?
ts->head.next = rootglobal.next;
rootglobal.next = (GCnode *)ts;
}
}
char *luaS_travsymbol (int32 (*fn)(TObject *)) {
TaggedString *g;
for (g = (TaggedString *)rootglobal.next; g; g = (TaggedString *)g->head.next)
if (fn(&g->globalval))
return g->str;
return nullptr;
}
int32 luaS_globaldefined(const char *name) {
TaggedString *ts = luaS_new(name);
return ts->globalval.ttype != LUA_T_NIL;
}
} // end of namespace Grim

View File

@@ -0,0 +1,31 @@
/*
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
#ifndef LSTRING_H
#define LSTRING_H
#include "engines/grim/lua/lobject.h"
namespace Grim {
void luaS_init();
TaggedString *luaS_createudata(void *udata, int32 tag);
TaggedString *luaS_collector();
void luaS_free (TaggedString *l);
TaggedString *luaS_new(const char *str);
TaggedString *luaS_newfixedstring (const char *str);
void luaS_rawsetglobal(TaggedString *ts, TObject *newval);
char *luaS_travsymbol(int32 (*fn)(TObject *));
int32 luaS_globaldefined(const char *name);
TaggedString *luaS_collectudata();
void luaS_freeall();
extern TaggedString EMPTY;
#define NUM_HASHS 61
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,503 @@
/*
** Standard library for strings and pattern-matching
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_iscntrl
#define FORBIDDEN_SYMBOL_EXCEPTION_ispunct
#define FORBIDDEN_SYMBOL_EXCEPTION_sprintf
#include "common/util.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/lualib.h"
namespace Grim {
static void addnchar(const char *s, int32 n) {
char *b = luaL_openspace(n);
strncpy(b, s, n);
luaL_addsize(n);
}
static void addstr(const char *s) {
addnchar(s, strlen(s));
}
static void str_len() {
lua_pushnumber(strlen(luaL_check_string(1)));
}
static void closeandpush() {
luaL_addchar(0);
lua_pushstring(luaL_buffer());
}
static void str_sub() {
const char *s = luaL_check_string(1);
int l = strlen(s);
int start = (int)luaL_check_number(2);
int end = (int)luaL_opt_number(3, -1);
if (start < 0)
start = l + start + 1;
if (end < 0)
end = l + end + 1;
if (1 <= start && start <= end && end <= l) {
luaL_resetbuffer();
addnchar(s + start - 1, end - start + 1);
closeandpush();
} else
lua_pushstring("");
}
static void str_lower() {
const char *s;
luaL_resetbuffer();
for (s = luaL_check_string(1); *s; s++)
luaL_addchar(tolower((byte)*s));
closeandpush();
}
static void str_upper() {
const char *s;
luaL_resetbuffer();
for (s = luaL_check_string(1); *s; s++)
luaL_addchar(toupper((byte)*s));
closeandpush();
}
static void str_rep() {
const char *s = luaL_check_string(1);
int32 n = (int32)luaL_check_number(2);
luaL_resetbuffer();
while (n-- > 0)
addstr(s);
closeandpush();
}
#define MAX_CAPT 9
struct Capture {
int32 level; // total number of captures (finished or unfinished)
struct {
const char *init;
int32 len; // -1 signals unfinished capture
} capture[MAX_CAPT];
};
#define ESC '%'
#define SPECIALS "^$*?.([%-"
static void push_captures(Capture *cap) {
for (int i = 0; i < cap->level; i++) {
int l = cap->capture[i].len;
char *buff = luaL_openspace(l+1);
if (l < 0)
lua_error("unfinished capture");
strncpy(buff, cap->capture[i].init, l);
buff[l] = 0;
lua_pushstring(buff);
}
}
static int32 check_cap (int32 l, Capture *cap) {
l -= '1';
if (!(0 <= l && l < cap->level && cap->capture[l].len != -1))
lua_error("invalid capture index");
return l;
}
static int32 capture_to_close(Capture *cap) {
int32 level = cap->level;
for (level--; level >= 0; level--)
if (cap->capture[level].len == -1) return level;
lua_error("invalid pattern capture");
return 0; // to avoid warnings
}
static const char *bracket_end(const char *p) {
return (*p == 0) ? nullptr : strchr((*p == '^') ? p + 2 : p + 1, ']');
}
static int32 matchclass(int32 c, int32 cl) {
int32 res;
if (c == 0)
return 0;
switch (tolower((int)cl)) {
case 'a' :
res = Common::isAlpha(c);
break;
case 'c' :
res = iscntrl(c);
break;
case 'd' :
res = Common::isDigit(c);
break;
case 'l' :
res = Common::isLower(c);
break;
case 'p' :
res = ispunct(c);
break;
case 's' :
res = Common::isSpace(c);
break;
case 'u' :
res = Common::isUpper(c);
break;
case 'w' :
res = Common::isAlnum(c);
break;
default:
return (cl == c);
}
return (Common::isLower((byte)cl) ? res : !res);
}
int32 luaI_singlematch(int32 c, const char *p, const char **ep) {
switch (*p) {
case '.': // matches any char
*ep = p + 1;
return c != 0;
case '\0': // end of pattern; matches nothing
*ep = p;
return 0;
case ESC:
if (*(++p) == '\0')
luaL_verror("incorrect pattern (ends with `%c')", ESC);
*ep = p+1;
return matchclass(c, (byte)*p);
case '[': {
const char *end = bracket_end(p + 1);
int32 sig = *(p + 1) == '^' ? (p++, 0) : 1;
if (!end)
lua_error("incorrect pattern (missing `]')");
*ep = end + 1;
if (c == 0)
return 0;
while (++p < end) {
if (*p == ESC) {
if (((p + 1) < end) && matchclass(c, (byte)*++p))
return sig;
} else if ((*(p + 1) == '-') && (p + 2 < end)) {
p += 2;
if ((byte)*(p - 2) <= c && c <= (byte)*p)
return sig;
} else if ((byte)*p == c)
return sig;
}
return !sig;
}
default:
*ep = p+1;
return ((byte)*p == c);
}
}
static const char *matchbalance(const char *s, int32 b, int32 e) {
if (*s != b)
return nullptr;
else {
int32 cont = 1;
while (*(++s)) {
if (*s == e) {
if (--cont == 0)
return s + 1;
} else if (*s == b)
cont++;
}
}
return nullptr; // string ends out of balance
}
static const char *matchitem(const char *s, const char *p, Capture *cap, const char **ep) {
if (*p == ESC) {
p++;
if (Common::isDigit((byte)*p)) { // capture
int32 l = check_cap(*p, cap);
*ep = p + 1;
if (strncmp(cap->capture[l].init, s, cap->capture[l].len) == 0)
return s + cap->capture[l].len;
else
return nullptr;
} else if (*p == 'b') { // balanced string
p++;
if (*p == 0 || *(p + 1) == 0)
lua_error("unbalanced pattern");
*ep = p + 2;
return matchbalance(s, *p, *(p + 1));
} else
p--; // and go through
}
return (luaI_singlematch((byte)*s, p, ep) ? s + 1 : nullptr);
}
static const char *match(const char *s, const char *p, Capture *cap) {
init:
// using goto's to optimize tail recursion
switch (*p) {
case '(':
{ // start capture
const char *res;
if (cap->level >= MAX_CAPT)
lua_error("too many captures");
cap->capture[cap->level].init = s;
cap->capture[cap->level].len = -1;
cap->level++;
res = match(s, p + 1, cap);
if (!res) // match failed?
cap->level--; // undo capture
return res;
}
case ')':
{ // end capture
int32 l = capture_to_close(cap);
const char *res;
cap->capture[l].len = s - cap->capture[l].init; // close capture
res = match(s, p + 1, cap);
if (!res) // match failed?
cap->capture[l].len = -1; // undo capture
return res;
}
case '\0':
case '$': // (possibly) end of pattern
if (*p == 0 || (*(p + 1) == 0 && *s == 0))
return s;
// fall through
default:
{ // it is a pattern item
const char *ep; // get what is next
const char *s1 = matchitem(s, p, cap, &ep);
switch (*ep) {
case '*':
{ // repetition
const char *res;
if (s1) {
res = match(s1, p, cap);
return res;
}
p = ep + 1;
goto init;
}
case '?':
{ // optional
const char *res;
if (s1) {
res = match(s1, ep + 1, cap);
return res;
}
p = ep + 1;
goto init;
}
case '-':
{ // repetition
const char *res = match(s, ep + 1, cap);
if (res)
return res;
else if (s1) {
s = s1;
goto init;
} else
return nullptr;
}
default:
if (s1) {
s = s1;
p = ep;
goto init;
} else
return nullptr;
}
}
}
}
static void str_find() {
const char *s = luaL_check_string(1);
const char *p = luaL_check_string(2);
int32 init = (uint32)luaL_opt_number(3, 1) - 1;
luaL_arg_check(0 <= init && init <= (int32)strlen(s), 3, "out of range");
if (lua_getparam(4) != LUA_NOOBJECT || !strpbrk(p, SPECIALS)) { // no special characters?
const char *s2 = strstr(s + init, p);
if (s2) {
lua_pushnumber(s2 - s + 1);
lua_pushnumber(s2 - s + strlen(p));
}
} else {
int32 anchor = (*p == '^') ? (p++, 1) : 0;
const char *s1 = s + init;
do {
struct Capture cap;
const char *res;
cap.level = 0;
res = match(s1, p, &cap);
if (res) {
lua_pushnumber(s1 - s + 1); // start
lua_pushnumber(res - s); // end
push_captures(&cap);
return;
}
} while (*s1++ && !anchor);
}
}
static void add_s(lua_Object newp, Capture *cap) {
if (lua_isstring(newp)) {
const char *news = lua_getstring(newp);
while (*news) {
if (*news != ESC || !Common::isDigit((byte)*++news))
luaL_addchar(*news++);
else {
int l = check_cap(*news++, cap);
addnchar(cap->capture[l].init, cap->capture[l].len);
}
}
} else if (lua_isfunction(newp)) {
lua_Object res;
int32 status;
int32 oldbuff;
lua_beginblock();
push_captures(cap);
// function may use buffer, so save it and create a new one
oldbuff = luaL_newbuffer(0);
status = lua_callfunction(newp);
// restore old buffer
luaL_oldbuffer(oldbuff);
if (status) {
lua_endblock();
lua_error(nullptr);
}
res = lua_getresult(1);
addstr(lua_isstring(res) ? lua_getstring(res) : "");
lua_endblock();
} else
luaL_arg_check(0, 3, "string or function expected");
}
static void str_gsub() {
const char *src = luaL_check_string(1);
const char *p = luaL_check_string(2);
lua_Object newp = lua_getparam(3);
int32 max_s = (int32)luaL_opt_number(4, strlen(src) + 1);
int32 anchor = (*p == '^') ? (p++, 1) : 0;
int32 n = 0;
luaL_resetbuffer();
while (n < max_s) {
struct Capture cap;
const char *e;
cap.level = 0;
e = match(src, p, &cap);
if (e) {
n++;
add_s(newp, &cap);
}
if (e && e > src) // non empty match?
src = e; // skip it
else if (*src)
luaL_addchar(*src++);
else
break;
if (anchor)
break;
}
addstr(src);
closeandpush();
lua_pushnumber(n); // number of substitutions
}
static void luaI_addquoted(const char *s) {
luaL_addchar('"');
for (; *s; s++) {
if (strchr("\"\\\n", *s))
luaL_addchar('\\');
luaL_addchar(*s);
}
luaL_addchar('"');
}
#define MAX_FORMAT 200
static void str_format() {
int32 arg = 1;
const char *strfrmt = luaL_check_string(arg);
luaL_resetbuffer();
while (*strfrmt) {
if (*strfrmt != '%')
luaL_addchar(*strfrmt++);
else if (*++strfrmt == '%')
luaL_addchar(*strfrmt++); // %%
else { // format item
char form[MAX_FORMAT]; // store the format ('%...')
struct Capture cap;
char *buff;
const char *initf = strfrmt;
form[0] = '%';
cap.level = 0;
strfrmt = match(strfrmt, "%d?%$?[-+ #]*(%d*)%.?(%d*)", &cap);
if (cap.capture[0].len > 3 || cap.capture[1].len > 3) // < 1000?
lua_error("invalid format (width or precision too long)");
if (Common::isDigit((byte)initf[0]) && initf[1] == '$') {
arg = initf[0] - '0';
initf += 2; // skip the 'n$'
}
arg++;
strncpy(form+1, initf, strfrmt - initf + 1); // +1 to include conversion
form[strfrmt-initf + 2] = 0;
buff = luaL_openspace(1000); // to store the formatted value
switch (*strfrmt++) {
case 'q':
luaI_addquoted(luaL_check_string(arg));
continue;
case 's':
{
const char *s = luaL_check_string(arg);
buff = luaL_openspace(strlen(s));
snprintf(buff, strlen(s), form, s);
break;
}
case 'c':
case 'd':
case 'o':
case 'i':
case 'u':
case 'x':
case 'X':
snprintf(buff, 1000, form, (int)luaL_check_number(arg));
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
snprintf(buff, 1000, form, luaL_check_number(arg));
break;
default: // also treat cases 'pnLlh'
lua_error("invalid option in `format'");
}
luaL_addsize(strlen(buff));
}
}
closeandpush(); // push the result
}
static struct luaL_reg strlib[] = {
{"strlen", str_len},
{"strsub", str_sub},
{"strlower", str_lower},
{"strupper", str_upper},
{"strrep", str_rep},
{"format", str_format},
{"strfind", str_find},
{"gsub", str_gsub}
};
/*
** Open string library
*/
void strlib_open() {
luaL_openlib(strlib, (sizeof(strlib) / sizeof(strlib[0])));
}
} // end of namespace Grim

1511
engines/grim/lua/lstx.cpp Normal file

File diff suppressed because it is too large Load Diff

49
engines/grim/lua/lstx.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef LSTX_H
#define LSTX_H
namespace Grim {
typedef union {
int vInt;
float vReal;
char *pChar;
long vLong;
TaggedString *pTStr;
TProtoFunc *pFunc;
} YYSTYPE;
#define WRONGTOKEN 258
#define NIL 259
#define IF 260
#define THEN 261
#define ELSE 262
#define ELSEIF 263
#define WHILE 264
#define DO 265
#define REPEAT 266
#define UNTIL 267
#define END 268
#define RETURN 269
#define LOCAL 270
#define FUNCTION 271
#define DOTS 272
#define NUMBER 273
#define NAME 274
#define STRING 275
#define AND 276
#define OR 277
#define EQ 278
#define NE 279
#define LE 280
#define GE 281
#define CONC 282
#define UNARY 283
#define NOT 284
extern YYSTYPE luaY_lval;
} // end of namespace Grim
#endif

205
engines/grim/lua/ltable.cpp Normal file
View File

@@ -0,0 +1,205 @@
/*
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#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/ltable.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
#define gcsize(n) (1 + (n / 16))
#define nuse(t) ((t)->nuse)
#define nodevector(t) ((t)->node)
#define REHASH_LIMIT 0.70 // avoid more than this % full
#define TagDefault LUA_T_ARRAY;
static intptr hashindex(TObject *ref) {
intptr h;
switch (ttype(ref)) {
case LUA_T_NUMBER:
h = (intptr)nvalue(ref);
break;
case LUA_T_USERDATA:
h = (intptr)ref->value.ud.id;
break;
case LUA_T_STRING:
h = (intptr)tsvalue(ref);
break;
case LUA_T_ARRAY:
h = (intptr)avalue(ref);
break;
case LUA_T_PROTO:
h = (intptr)tfvalue(ref);
break;
case LUA_T_CPROTO:
h = (intptr)fvalue(ref);
break;
case LUA_T_CLOSURE:
h = (intptr)clvalue(ref);
break;
case LUA_T_TASK:
h = (intptr)nvalue(ref);
break;
default:
lua_error("unexpected type to index table");
h = 0; // to avoid warnings
}
return (h >= 0 ? h : -(h + 1));
}
int32 present(Hash *t, TObject *key) {
int32 tsize = nhash(t);
intptr h = hashindex(key);
int32 h1 = int32(h % tsize);
TObject *rf = ref(node(t, h1));
if (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf)) {
int32 h2 = int32(h % (tsize - 2) + 1);
do {
h1 += h2;
if (h1 >= tsize)
h1 -= tsize;
rf = ref(node(t, h1));
} while (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf));
}
return h1;
}
/*
** Alloc a vector node
*/
Node *hashnodecreate(int32 nhash) {
Node *v = luaM_newvector(nhash, Node);
int32 i;
for (i = 0; i < nhash; i++)
ttype(ref(&v[i])) = LUA_T_NIL;
return v;
}
/*
** Delete a hash
*/
static void hashdelete(Hash *t) {
luaM_free(nodevector(t));
luaM_free(t);
}
void luaH_free(Hash *frees) {
while (frees) {
Hash *next = (Hash *)frees->head.next;
nblocks -= gcsize(frees->nhash);
hashdelete(frees);
frees = next;
}
}
Hash *luaH_new(int32 nhash) {
Hash *t = luaM_new(Hash);
nhash = luaO_redimension((int32)((float)nhash / REHASH_LIMIT));
nodevector(t) = hashnodecreate(nhash);
nhash(t) = nhash;
nuse(t) = 0;
t->htag = TagDefault;
luaO_insertlist(&roottable, (GCnode *)t);
nblocks += gcsize(nhash);
return t;
}
/*
** Rehash:
** Check if table has deleted slots. It it has, it does not need to
** grow, since rehash will reuse them.
*/
static int emptyslots(Hash *t) {
int i;
for (i = nhash(t) - 1; i >= 0; i--) {
Node *n = node(t, i);
if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) == LUA_T_NIL)
return 1;
}
return 0;
}
static void rehash(Hash *t) {
int32 nold = nhash(t);
Node *vold = nodevector(t);
int32 i;
if (!emptyslots(t))
nhash(t) = luaO_redimension(nhash(t));
nodevector(t) = hashnodecreate(nhash(t));
for (i = 0; i < nold; i++) {
Node *n = vold + i;
if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) != LUA_T_NIL)
*node(t, present(t, ref(n))) = *n; // copy old node to luaM_new hash
}
nblocks += gcsize(t->nhash) - gcsize(nold);
luaM_free(vold);
}
/*
** If the hash node is present, return its pointer, otherwise return
** null.
*/
TObject *luaH_get(Hash *t, TObject *r) {
int32 h = present(t, r);
if (ttype(ref(node(t, h))) != LUA_T_NIL)
return val(node(t, h));
else
return nullptr;
}
/*
** If the hash node is present, return its pointer, otherwise create a luaM_new
** node for the given reference and also return its pointer.
*/
TObject *luaH_set(Hash *t, TObject *r) {
Node *n = node(t, present(t, r));
if (ttype(ref(n)) == LUA_T_NIL) {
nuse(t)++;
if ((float)nuse(t) > (float)nhash(t) * REHASH_LIMIT) {
rehash(t);
n = node(t, present(t, r));
}
*ref(n) = *r;
ttype(val(n)) = LUA_T_NIL;
}
return (val(n));
}
static Node *hashnext(Hash *t, int32 i) {
Node *n;
int32 tsize = nhash(t);
if (i >= tsize)
return nullptr;
n = node(t, i);
while (ttype(ref(n)) == LUA_T_NIL || ttype(val(n)) == LUA_T_NIL) {
if (++i >= tsize)
return nullptr;
n = node(t, i);
}
return node(t, i);
}
Node *luaH_next(TObject *o, TObject *r) {
Hash *t = avalue(o);
if (ttype(r) == LUA_T_NIL)
return hashnext(t, 0);
else {
int32 i = present(t, r);
Node *n = node(t, i);
luaL_arg_check(ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) != LUA_T_NIL, 2, "key not found");
return hashnext(t, i + 1);
}
}
} // end of namespace Grim

28
engines/grim/lua/ltable.h Normal file
View File

@@ -0,0 +1,28 @@
/*
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LTABLE_H
#define GRIM_LTABLE_H
#include "engines/grim/lua/lobject.h"
namespace Grim {
#define node(t, i) (&(t)->node[i])
#define ref(n) (&(n)->ref)
#define val(n) (&(n)->val)
#define nhash(t) ((t)->nhash)
Hash *luaH_new(int32 nhash);
void luaH_free(Hash *frees);
TObject *luaH_get(Hash *t, TObject *r);
TObject *luaH_set(Hash *t, TObject *r);
Node *luaH_next(TObject *o, TObject *r);
Node *hashnodecreate(int32 nhash);
int32 present(Hash *t, TObject *key);
} // end of namespace Grim
#endif

380
engines/grim/lua/ltask.cpp Normal file
View File

@@ -0,0 +1,380 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#include "engines/grim/lua/ltask.h"
#include "engines/grim/lua/lapi.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lvm.h"
#include "engines/grim/grim.h"
#include "common/textconsole.h"
namespace Grim {
void lua_taskinit(lua_Task *task, lua_Task *next, StkId tbase, int results) {
task->executed = false;
task->next = next;
task->initBase = tbase;
task->initResults = results;
}
void lua_taskresume(lua_Task *task, Closure *closure, TProtoFunc *protofunc, StkId tbase) {
task->cl = closure;
task->tf = protofunc;
task->base = tbase;
task->pc = task->tf->code;
task->consts = task->tf->consts;
task->S = &lua_state->stack;
}
void start_script() {
lua_Object paramObj = lua_getparam(1);
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
if (paramObj == LUA_NOOBJECT || (type != LUA_T_CPROTO && type != LUA_T_PROTO)) {
return;
}
LState *state = luaM_new(LState);
lua_stateinit(state);
state->next = lua_state->next;
state->prev = lua_state;
if (state->next)
state->next->prev = state;
lua_state->next = state;
state->taskFunc.ttype = type;
state->taskFunc.value = Address(paramObj)->value;
int l = 2;
for (lua_Object object = lua_getparam(l++); object != LUA_NOOBJECT; object = lua_getparam(l++)) {
TObject ptr;
ptr.ttype = Address(object)->ttype;
ptr.value = Address(object)->value;
LState *tmpState = lua_state;
lua_state = state;
luaA_pushobject(&ptr);
lua_state = tmpState;
}
ttype(lua_state->stack.top) = LUA_T_TASK;
nvalue(lua_state->stack.top) = (float)state->id;
incr_top;
}
void next_script() {
lua_Object paramObj = lua_getparam(1);
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
if (paramObj == LUA_NOOBJECT || (type != LUA_T_TASK && type != LUA_T_NIL))
lua_error("Bad argument to next_script");
if (type == LUA_T_TASK) {
uint32 task = (uint32)nvalue(Address(paramObj));
LState *state;
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (state->id == task) {
if (state->next) {
ttype(lua_state->stack.top) = LUA_T_TASK;
nvalue(lua_state->stack.top) = (float)state->next->id;
incr_top;
} else
lua_pushnil();
return;
}
}
}
if (lua_rootState->next) {
ttype(lua_state->stack.top) = LUA_T_TASK;
nvalue(lua_state->stack.top) = (float)lua_rootState->next->id;
incr_top;
} else
lua_pushnil();
}
void stop_script() {
lua_Object paramObj = lua_getparam(1);
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
LState *state;
if (paramObj == LUA_NOOBJECT || (type != LUA_T_CPROTO && type != LUA_T_PROTO && type != LUA_T_TASK))
lua_error("Bad argument to stop_script");
if (type == LUA_T_TASK) {
uint32 task = (uint32)nvalue(Address(paramObj));
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (state->id == task)
break;
}
if (state) {
if (state != lua_state) {
lua_statedeinit(state);
luaM_free(state);
}
}
} else if (type == LUA_T_PROTO || type == LUA_T_CPROTO) {
for (state = lua_rootState->next; state != nullptr;) {
bool match;
if (type == LUA_T_PROTO) {
match = (state->taskFunc.ttype == type && tfvalue(&state->taskFunc) == tfvalue(Address(paramObj)));
} else {
match = (state->taskFunc.ttype == type && fvalue(&state->taskFunc) == fvalue(Address(paramObj)));
}
if (match && state != lua_state) {
LState *tmp = state->next;
lua_statedeinit(state);
luaM_free(state);
state = tmp;
} else {
state = state->next;
}
}
}
}
void identify_script() {
lua_Object paramObj = lua_getparam(1);
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
if (paramObj == LUA_NOOBJECT || type != LUA_T_TASK)
lua_error("Bad argument to identify_script");
uint32 task = (uint32)nvalue(Address(paramObj));
LState *state;
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (state->id == task) {
luaA_pushobject(&state->taskFunc);
return;
}
}
lua_pushnil();
}
void find_script() {
lua_Object paramObj = lua_getparam(1);
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
if (type != LUA_T_CPROTO && type != LUA_T_PROTO && type != LUA_T_TASK && type != LUA_T_NIL)
lua_error("Bad argument to find_script");
if (type == LUA_T_NIL) {
ttype(lua_state->stack.top) = LUA_T_TASK;
nvalue(lua_state->stack.top) = lua_state->id;
incr_top;
lua_pushnumber(1.0f);
return;
}
if (type == LUA_T_TASK) {
uint32 task = (uint32)nvalue(Address(paramObj));
LState *state;
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (state->id == task) {
lua_pushobject(paramObj);
lua_pushnumber(1.0f);
return;
}
}
} else if (type == LUA_T_PROTO || type == LUA_T_CPROTO) {
int task = -1, countTasks = 0;
bool match;
LState *state;
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (type == LUA_T_PROTO) {
match = (state->taskFunc.ttype == type && tfvalue(&state->taskFunc) == tfvalue(Address(paramObj)));
} else {
match = (state->taskFunc.ttype == type && fvalue(&state->taskFunc) == fvalue(Address(paramObj)));
}
if (match) {
task = state->id;
countTasks++;
}
}
if (countTasks) {
assert(task != -1);
ttype(lua_state->stack.top) = LUA_T_TASK;
nvalue(lua_state->stack.top) = (float)task;
incr_top;
lua_pushnumber((float)countTasks);
return;
}
}
lua_pushnil();
lua_pushnumber(0.0f);
}
void pause_script() {
lua_Object taskObj = lua_getparam(1);
lua_Type type = taskObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(taskObj));
if (type != LUA_T_TASK) {
lua_error("Bad argument to pause_script");
return;
}
uint32 task = (uint32)nvalue(Address(taskObj));
LState *state;
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (state->id == task) {
state->paused = true;
return;
}
}
}
void pause_scripts() {
LState *t;
lua_Object boolObj = lua_getparam(1);
bool p = false;
if (!lua_isnil(boolObj))
p = true;
for (t = lua_rootState->next; t != nullptr; t = t->next) {
if (lua_state != t) {
if (p) {
t->all_paused++;
} else {
t->all_paused = 1;
}
}
}
}
void unpause_script() {
lua_Object taskObj = lua_getparam(1);
lua_Type type = taskObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(taskObj));
if (type != LUA_T_TASK) {
lua_error("Bad argument to unpause_script");
return;
}
uint32 task = (uint32)nvalue(Address(taskObj));
LState *state;
for (state = lua_rootState->next; state != nullptr; state = state->next) {
if (state->id == task) {
state->paused = false;
return;
}
}
}
void unpause_scripts() {
LState *t;
lua_Object boolObj = lua_getparam(1);
bool p = false;
if (!lua_isnil(boolObj))
p = true;
for (t = lua_rootState->next; t != nullptr; t = t->next) {
if (lua_state != t) {
if (p) {
if (t->all_paused > 0)
t->all_paused--;
} else {
t->all_paused = 0;
}
}
}
}
void current_script() {
ttype(lua_state->stack.top) = LUA_T_TASK;
nvalue(lua_state->stack.top) = (float)lua_state->id;
incr_top;
}
void break_here() {}
void sleep_for() {
lua_Object msObj = lua_getparam(1);
if (lua_isnumber(msObj)) {
int ms = (int)lua_getnumber(msObj);
lua_state->sleepFor = ms;
}
}
void lua_runtasks() {
if (!lua_state || !lua_state->next) {
return;
}
// Mark all the states to be updated
LState *state = lua_state->next;
do {
if (state->sleepFor > 0) {
state->sleepFor -= g_grim->getFrameTime();
} else {
state->updated = false;
}
state = state->next;
} while (state);
// And run them
runtasks(lua_state);
}
void runtasks(LState *const rootState) {
lua_state = lua_state->next;
while (lua_state) {
LState *nextState = nullptr;
bool stillRunning;
if (!lua_state->all_paused && !lua_state->updated && !lua_state->paused) {
jmp_buf errorJmp;
lua_state->errorJmp = &errorJmp;
if (setjmp(errorJmp)) {
lua_Task *t, *m;
for (t = lua_state->task; t != nullptr;) {
m = t->next;
luaM_free(t);
t = m;
}
stillRunning = false;
lua_state->task = nullptr;
} else {
if (lua_state->task) {
stillRunning = luaD_call(lua_state->task->initBase, lua_state->task->initResults);
} else {
StkId base = lua_state->Cstack.base;
luaD_openstack((lua_state->stack.top - lua_state->stack.stack) - base);
set_normalized(lua_state->stack.stack + lua_state->Cstack.base, &lua_state->taskFunc);
stillRunning = luaD_call(base + 1, 255);
}
}
nextState = lua_state->next;
// The state returned. Delete it
if (!stillRunning) {
lua_statedeinit(lua_state);
luaM_free(lua_state);
} else {
lua_state->updated = true;
}
} else {
nextState = lua_state->next;
}
lua_state = nextState;
}
// Restore the value of lua_state to the main script
lua_state = rootState;
// Check for states that may have been created in this run.
LState *state = lua_state->next;
while (state) {
if (!state->all_paused && !state->paused && !state->updated) {
// New state! Run a new pass.
runtasks(rootState);
return;
}
state = state->next;
}
}
} // end of namespace Grim

35
engines/grim/lua/ltask.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef GRIM_LTASK_H
#define GRIM_LTASK_H
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/lstate.h"
#include "engines/grim/lua/lbuiltin.h"
namespace Grim {
struct lua_Task {
lua_Task *next;
struct Stack *S;
Closure *cl;
TProtoFunc *tf;
StkId base;
byte *pc;
TObject *consts;
int32 aux;
bool executed;
StkId initBase;
int32 initResults;
};
void lua_taskinit(lua_Task *task, lua_Task *next, StkId tbase, int results);
void lua_taskresume(lua_Task *task, Closure *closure, TProtoFunc *protofunc, StkId tbase);
StkId luaV_execute(lua_Task *task);
void pause_script();
void unpause_script();
void runtasks(LState *const rootState);
} // end of namespace Grim
#endif

248
engines/grim/lua/ltm.cpp Normal file
View File

@@ -0,0 +1,248 @@
/*
** 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

62
engines/grim/lua/ltm.h Normal file
View File

@@ -0,0 +1,62 @@
/*
** Tag methods
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LTM_H
#define GRIM_LTM_H
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lstate.h"
namespace Grim {
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER IM"
*/
typedef enum {
IM_GETTABLE = 0,
IM_SETTABLE,
IM_INDEX,
IM_GETGLOBAL,
IM_SETGLOBAL,
IM_ADD,
IM_SUB,
IM_MUL,
IM_DIV,
IM_POW,
IM_UNM,
IM_LT,
IM_LE,
IM_GT,
IM_GE,
IM_CONCAT,
IM_GC,
IM_FUNCTION
} eIMS;
typedef int32 IMS;
#define IM_N 18
struct IM {
TObject int_method[IM_N];
};
#define luaT_getim(tag, event) (&IMtable[-(tag)].int_method[event])
#define luaT_getimbyObj(o, e) (luaT_getim(luaT_efectivetag(o), (e)))
extern const char *luaT_eventname[];
void luaT_init();
void luaT_realtag(int32 tag);
int32 luaT_efectivetag(TObject *o);
void luaT_settagmethod(int32 t, const char *event, TObject *func);
TObject *luaT_gettagmethod(int32 t, const char *event);
const char *luaT_travtagmethods(int32 (*fn)(TObject *));
void luaT_setfallback(); // only if LUA_COMPAT2_5
} // end of namespace Grim
#endif

219
engines/grim/lua/lua.h Normal file
View File

@@ -0,0 +1,219 @@
/*
** Lua - An Extensible Extension Language
** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
** e-mail: lua@tecgraf.puc-rio.br
** www: http://www.tecgraf.puc-rio.br/lua/
** See Copyright Notice at the end of this file
*/
#ifndef GRIM_LUA_H
#define GRIM_LUA_H
#include "common/scummsys.h"
#include "common/str.h"
namespace Common {
class String;
class SeekableReadStream;
class WriteStream;
class File;
}
namespace Grim {
#define LUA_VERSION "Lua 3.1 (alpha)"
#define LUA_COPYRIGHT "Copyright (C) 1994-1998 TeCGraf, PUC-Rio"
#define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo"
#define LUA_NOOBJECT 0
#define LUA_ANYTAG (-1)
typedef void (*lua_CFunction)();
typedef uint32 lua_Object;
struct PointerId {
uint64 id;
};
PointerId makeIdFromPointer(void *ptr);
void *makePointerFromId(PointerId ptr);
class LuaFile {
public:
Common::String _name;
Common::String _filename;
Common::SeekableReadStream *_in;
Common::WriteStream *_out;
bool _stdin, _stdout, _stderr;
public:
LuaFile();
~LuaFile();
void close();
bool isOpen() const;
uint32 read(void *buf, uint32 len);
uint32 write(const char *buf, uint32 len);
void seek(int32 pos, int whence = 0);
};
class SaveGame;
void lua_Save(SaveGame *state);
void lua_Restore(SaveGame *state);
void lua_removelibslists();
void lua_open();
void lua_close();
bool lua_isopen();
lua_Object lua_settagmethod(int32 tag, const char *event); // In: new method
lua_Object lua_gettagmethod(int32 tag, const char *event);
lua_Object lua_seterrormethod(); // In: new method
int32 lua_newtag();
int32 lua_copytagmethods(int32 tagto, int32 tagfrom);
void lua_settag(int32 tag); // In: object
void NORETURN_PRE lua_error(const char *s) NORETURN_POST;
int32 lua_dostring(const char *string); // Out: returns
int32 lua_dobuffer(const char *buff, int32 size, const char *name);
int32 lua_callfunction(lua_Object f);
// In: parameters; Out: returns */
void lua_beginblock();
void lua_endblock();
lua_Object lua_lua2C(int32 number);
#define lua_getparam(_) lua_lua2C(_)
#define lua_getresult(_) lua_lua2C(_)
int32 lua_isnil (lua_Object object);
int32 lua_istable (lua_Object object);
int32 lua_isuserdata (lua_Object object);
int32 lua_iscfunction (lua_Object object);
int32 lua_isnumber (lua_Object object);
int32 lua_isstring (lua_Object object);
int32 lua_isfunction (lua_Object object);
float lua_getnumber (lua_Object object);
const char *lua_getstring (lua_Object object);
lua_CFunction lua_getcfunction (lua_Object object);
int32 lua_getuserdata (lua_Object object);
void lua_pushnil();
void lua_pushnumber(float n);
void lua_pushstring(const char *s);
void lua_pushCclosure(lua_CFunction fn, int32 n);
void lua_pushusertag(int32 id, int32 tag);
void lua_pushobject(lua_Object object);
lua_Object lua_pop();
lua_Object lua_getglobal(const char *name);
lua_Object lua_rawgetglobal(const char *name);
void lua_setglobal(const char *name); // In: value
void lua_rawsetglobal(const char *name); // In: value
void lua_settable(); // In: table, index, value
void lua_rawsettable(); // In: table, index, value
lua_Object lua_gettable(); // In: table, index
lua_Object lua_rawgettable(); // In: table, index
int32 lua_tag(lua_Object object);
int32 lua_ref(int32 lock); // In: value
lua_Object lua_getref(int32 ref);
void lua_unref(int32 ref);
lua_Object lua_createtable();
int32 lua_collectgarbage(int32 limit);
void lua_runtasks();
void current_script();
/* some useful macros/derived functions */
#define lua_call(name) lua_callfunction(lua_getglobal(name))
#define lua_pushref(ref) lua_pushobject(lua_getref(ref))
#define lua_refobject(o,l) (lua_pushobject(o), lua_ref(l))
#define lua_register(n, f) (lua_pushcfunction(f), lua_setglobal(n))
#define lua_pushuserdata(u) lua_pushusertag(u, 0)
#define lua_pushcfunction(f) lua_pushCclosure(f, 0)
#define lua_clonetag(t) lua_copytagmethods(lua_newtag(), (t))
/* ==========================================================================
** for compatibility with old versions. Avoid using these macros/functions
** If your program does need any of these, define LUA_COMPAT2_5
*/
#define LUA_COMPAT2_5
#ifdef LUA_COMPAT2_5
lua_Object lua_setfallback(const char *event, lua_CFunction fallback);
#define lua_storeglobal lua_setglobal
#define lua_type lua_tag
#define lua_lockobject(o) lua_refobject(o,1)
#define lua_lock() lua_ref(1)
#define lua_getlocked lua_getref
#define lua_pushlocked lua_pushref
#define lua_unlock lua_unref
#define lua_pushliteral(o) lua_pushstring(o)
#define lua_getindexed(o, n) (lua_pushobject(o), lua_pushnumber(n), lua_gettable())
#define lua_getfield(o, f) (lua_pushobject(o), lua_pushstring(f), lua_gettable())
#define lua_copystring(o) (strdup(lua_getstring(o)))
#define lua_getsubscript lua_gettable
#define lua_storesubscript lua_settable
#endif
/******************************************************************************
* Copyright (c) 1994-1998 TeCGraf, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, without written agreement and without license
* or royalty fees, to use, copy, modify, and distribute this software and its
* documentation for any purpose, including commercial applications, subject to
* the following conditions:
*
* - The above copyright notice and this permission notice shall appear in all
* copies or substantial portions of this software.
*
* - The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be greatly
* appreciated (but it is not required).
*
* - Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* The authors specifically disclaim any warranties, including, but not limited
* to, the implied warranties of merchantability and fitness for a particular
* purpose. The software provided hereunder is on an "as is" basis, and the
* authors have no obligation to provide maintenance, support, updates,
* enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the
* authors be held liable to any party for direct, indirect, special,
* incidental, or consequential damages arising out of the use of this software
* and its documentation.
*
* The Lua language and this implementation have been entirely designed and
* written by Waldemar Celes Filho, Roberto Ierusalimschy and
* Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio.
*
* NOTE: This implementation of Lua contains additional code and
* modifications added only for ScummVM project.
* Look into the source code file "Changelog" for more info.
******************************************************************************/
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,35 @@
/*
** Debugging API
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LUADEBUG_H
#define GRIM_LUADEBUG_H
#include "engines/grim/lua/lua.h"
namespace Grim {
typedef lua_Object lua_Function;
typedef void (*lua_LHFunction)(int32 line);
typedef void (*lua_CHFunction)(lua_Function func, const char *file, int32 line);
lua_Function lua_stackedfunction(int32 level);
void lua_funcinfo(lua_Object func, const char **filename, int32 *linedefined);
int32 lua_currentline(lua_Function func);
const char *lua_getobjname(lua_Object o, const char **name);
lua_Object lua_getlocal(lua_Function func, int32 local_number, char **name);
int32 lua_setlocal(lua_Function func, int32 local_number);
extern lua_LHFunction lua_linehook;
extern lua_CHFunction lua_callhook;
extern int32 lua_debug;
} // end of namespace Grim
#endif

32
engines/grim/lua/lualib.h Normal file
View File

@@ -0,0 +1,32 @@
/*
** Lua standard libraries
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LUALIB_H
#define GRIM_LUALIB_H
#include "engines/grim/lua/lua.h"
namespace Grim {
void lua_iolibopen();
void lua_strlibopen();
void lua_mathlibopen();
void lua_iolibclose();
// To keep compatibility with old versions
#define iolib_open lua_iolibopen
#define strlib_open lua_strlibopen
#define mathlib_open lua_mathlibopen
// Auxiliary functions (private)
int32 luaI_singlematch(int32 c, const char *p, const char **ep);
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,187 @@
/*
** load bytecodes from files
** See Copyright Notice in lua.h
*/
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lstring.h"
#include "engines/grim/lua/lundump.h"
namespace Grim {
static float conv_float(const byte *data) {
float f;
byte *fdata = (byte *)(&f);
fdata[0] = data[3];
fdata[1] = data[2];
fdata[2] = data[1];
fdata[3] = data[0];
return f;
}
static void unexpectedEOZ(ZIO *Z) {
luaL_verror("unexpected end of file in %s", zname(Z));
}
static int32 ezgetc(ZIO *Z) {
int32 c = zgetc(Z);
if (c == EOZ)
unexpectedEOZ(Z);
return c;
}
static void ezread(ZIO *Z, void *b, int32 n) {
int32 r = zread(Z, b, n);
if (r)
unexpectedEOZ(Z);
}
static uint16 LoadWord(ZIO *Z) {
uint16 hi = ezgetc(Z);
uint16 lo = ezgetc(Z);
return (hi << 8) | lo;
}
static void *LoadBlock(int size, ZIO *Z) {
void *b = luaM_malloc(size);
ezread(Z, b, size);
return b;
}
static uint32 LoadSize(ZIO *Z) {
uint32 hi = LoadWord(Z);
uint32 lo = LoadWord(Z);
return (hi << 16) | lo;
}
static float LoadFloat(ZIO *Z) {
uint32 l = LoadSize(Z);
return conv_float((const byte *)&l);
}
static TaggedString *LoadTString(ZIO *Z) {
int32 size = LoadWord(Z);
int32 i;
if (size == 0)
return nullptr;
else {
char *s = luaL_openspace(size);
ezread(Z, s, size);
for (i = 0; i < size; i++)
s[i] ^= 0xff;
return luaS_new(s);
}
}
static void LoadLocals(TProtoFunc *tf, ZIO *Z) {
int32 i, n = LoadWord(Z);
if (n == 0)
return;
tf->locvars = luaM_newvector(n + 1, LocVar);
for (i = 0; i < n; i++) {
tf->locvars[i].line = LoadWord(Z);
tf->locvars[i].varname = LoadTString(Z);
}
tf->locvars[i].line = -1; // flag end of vector
tf->locvars[i].varname = nullptr;
}
static void LoadConstants(TProtoFunc *tf, ZIO *Z) {
int32 i, n = LoadWord(Z);
tf->nconsts = n;
if (n == 0)
return;
tf->consts = luaM_newvector(n, TObject);
for (i = 0; i < n; i++) {
TObject *o = tf->consts + i;
int c = ezgetc(Z);
switch (c) {
case ID_NUM:
ttype(o) = LUA_T_NUMBER;
nvalue(o) = LoadFloat(Z);
break;
case ID_STR:
ttype(o) = LUA_T_STRING;
tsvalue(o) = LoadTString(Z);
break;
case ID_FUN:
ttype(o) = LUA_T_PROTO;
tfvalue(o) = nullptr;
default:
break;
}
}
}
static void LoadFunctions(TProtoFunc *tf, ZIO *Z);
static TProtoFunc *LoadFunction(ZIO *Z) {
TProtoFunc *tf = luaF_newproto();
tf->lineDefined = LoadWord(Z);
tf->fileName = LoadTString(Z);
tf->code = (byte *)LoadBlock(LoadSize(Z), Z);
LoadConstants(tf, Z);
LoadLocals(tf, Z);
LoadFunctions(tf, Z);
return tf;
}
static void LoadFunctions(TProtoFunc *tf, ZIO *Z) {
while (ezgetc(Z) == ID_FUNCTION) {
int32 i = LoadWord(Z);
TProtoFunc *t = LoadFunction(Z);
TObject *o = tf->consts + i;
tfvalue(o) = t;
}
}
static void LoadSignature(ZIO *Z) {
const char *s = SIGNATURE;
while (*s && ezgetc(Z) == *s)
++s;
if (*s)
luaL_verror("bad signature in %s", zname(Z));
}
static void LoadHeader(ZIO *Z) {
int32 version, sizeofR;
LoadSignature(Z);
version = ezgetc(Z);
if (version > VERSION)
luaL_verror("%s too new: version=0x%02x; expected at most 0x%02x", zname(Z), version, VERSION);
if (version < VERSION) // check last major change
luaL_verror("%s too old: version=0x%02x; expected at least 0x%02x", zname(Z), version, VERSION);
sizeofR = ezgetc(Z); // test number representation
if (sizeofR != sizeof(float))
luaL_verror("number expected float in %s", zname(Z));
ezgetc(Z);
ezgetc(Z);
ezgetc(Z);
ezgetc(Z);
}
static TProtoFunc *LoadChunk(ZIO *Z) {
LoadHeader(Z);
return LoadFunction(Z);
}
/*
** load one chunk from a file or buffer
** return main if ok and NULL at EOF
*/
TProtoFunc *luaU_undump1(ZIO *Z) {
int32 c = zgetc(Z);
if (c == ID_CHUNK)
return LoadChunk(Z);
else if (c != EOZ)
luaL_verror("%s is not a Lua binary file", zname(Z));
return nullptr;
}
} // end of namespace Grim

View File

@@ -0,0 +1,32 @@
/*
** load pre-compiled Lua chunks
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LUNDUMP_H
#define GRIM_LUNDUMP_H
#include "engines/grim/lua/lobject.h"
#include "engines/grim/lua/lzio.h"
namespace Grim {
#define ID_CHUNK 27 // ESC
#define ID_FUNCTION '#'
#define ID_END '$'
#define ID_NUM 'N'
#define ID_STR 'S'
#define ID_FUN 'F'
#define SIGNATURE "Lua"
#define VERSION 0x31 // last format change was in 3.1
#define TEST_FLOAT 0.123456789e-23 // a float for testing representation
#define IsMain(f) (f->lineDefined == 0)
TProtoFunc *luaU_undump1(ZIO *Z); // load one chunk
} // end of namespace Grim
#endif

695
engines/grim/lua/lvm.cpp Normal file
View File

@@ -0,0 +1,695 @@
/*
** Lua virtual machine
** See Copyright Notice in lua.h
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
#define FORBIDDEN_SYMBOL_EXCEPTION_sprintf
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lfunc.h"
#include "engines/grim/lua/lgc.h"
#include "engines/grim/lua/lmem.h"
#include "engines/grim/lua/lopcodes.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/luadebug.h"
#include "engines/grim/lua/lvm.h"
namespace Grim {
#define skip_word(pc) (pc += 2)
#define get_word(pc) ((*((pc) + 1) << 8)|(*(pc)))
#define next_word(pc) (pc += 2, get_word(pc - 2))
#define EXTRA_STACK 5
static TaggedString *strconc(char *l, char *r) {
size_t nl = strlen(l);
char *buffer = luaL_openspace(nl + strlen(r) + 1);
strcpy(buffer, l);
strcpy(buffer + nl, r);
return luaS_new(buffer);
}
int32 luaV_tonumber (TObject *obj) { // LUA_NUMBER
double t;
char c;
if (ttype(obj) != LUA_T_STRING)
return 1;
else if (sscanf(svalue(obj), "%lf %c", &t, &c) == 1) {
nvalue(obj) = (float)t;
ttype(obj) = LUA_T_NUMBER;
return 0;
} else
return 2;
}
int32 luaV_tostring (TObject *obj) { // LUA_NUMBER
if (ttype(obj) != LUA_T_NUMBER)
return 1;
else {
char s[60];
float f = nvalue(obj);
int32 i;
if ((float)(-MAX_INT) <= f && f <= (float)MAX_INT && (float)(i = (int32)f) == f)
snprintf (s, 60, "%d", (int)i);
else
snprintf (s, 60, "%g", (double)nvalue(obj));
tsvalue(obj) = luaS_new(s);
ttype(obj) = LUA_T_STRING;
return 0;
}
}
void luaV_closure(int32 nelems) {
if (nelems > 0) {
Stack *S = &lua_state->stack;
Closure *c = luaF_newclosure(nelems);
c->consts[0] = *(S->top - 1);
memcpy(&c->consts[1], S->top - (nelems + 1), nelems * sizeof(TObject));
S->top -= nelems;
ttype(S->top - 1) = LUA_T_CLOSURE;
(S->top - 1)->value.cl = c;
}
}
/*
** Function to index a table.
** Receives the table at top-2 and the index at top-1.
*/
void luaV_gettable() {
Stack *S = &lua_state->stack;
TObject *im;
if (ttype(S->top - 2) != LUA_T_ARRAY) // not a table, get "gettable" method
im = luaT_getimbyObj(S->top - 2, IM_GETTABLE);
else { // object is a table...
int32 tg = (S->top - 2)->value.a->htag;
im = luaT_getim(tg, IM_GETTABLE);
if (ttype(im) == LUA_T_NIL) { // and does not have a "gettable" method
TObject *h = luaH_get(avalue(S->top - 2), S->top - 1);
if (h && ttype(h) != LUA_T_NIL) {
--S->top;
*(S->top - 1) = *h;
} else if (ttype(im = luaT_getim(tg, IM_INDEX)) != LUA_T_NIL)
luaD_callTM(im, 2, 1);
else {
--S->top;
ttype(S->top - 1) = LUA_T_NIL;
}
return;
}
// else it has a "gettable" method, go through to next command
}
// object is not a table, or it has a "gettable" method
if (ttype(im) != LUA_T_NIL)
luaD_callTM(im, 2, 1);
else
lua_error("indexed expression not a table");
}
/*
** Function to store indexed based on values at the stack.top
** mode = 0: raw store (without tag methods)
** mode = 1: normal store (with tag methods)
** mode = 2: "deep lua_state->stack.stack" store (with tag methods)
*/
void luaV_settable(TObject *t, int32 mode) {
struct Stack *S = &lua_state->stack;
TObject *im = (mode == 0) ? nullptr : luaT_getimbyObj(t, IM_SETTABLE);
if (ttype(t) == LUA_T_ARRAY && (!im || ttype(im) == LUA_T_NIL)) {
TObject *h = luaH_set(avalue(t), t + 1);
*h = *(S->top - 1);
S->top -= (mode == 2) ? 1 : 3;
} else { // object is not a table, and/or has a specific "settable" method
if (im && ttype(im) != LUA_T_NIL) {
if (mode == 2) {
*(S->top + 1) = *(lua_state->stack.top - 1);
*(S->top) = *(t + 1);
*(S->top - 1) = *t;
S->top += 2; // WARNING: caller must assure stack space
}
luaD_callTM(im, 3, 0);
} else
lua_error("indexed expression not a table");
}
}
void luaV_getglobal(TaggedString *ts) {
// WARNING: caller must assure stack space
TObject *value = &ts->globalval;
TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL);
if (ttype(im) == LUA_T_NIL) { // default behavior
*lua_state->stack.top++ = *value;
} else {
Stack *S = &lua_state->stack;
ttype(S->top) = LUA_T_STRING;
tsvalue(S->top) = ts;
S->top++;
*S->top++ = *value;
luaD_callTM(im, 2, 1);
}
}
void luaV_setglobal(TaggedString *ts) {
TObject *oldvalue = &ts->globalval;
TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL);
if (ttype(im) == LUA_T_NIL) // default behavior */
luaS_rawsetglobal(ts, --lua_state->stack.top);
else {
// WARNING: caller must assure stack space
Stack *S = &lua_state->stack;
TObject newvalue = *(S->top - 1);
ttype(S->top - 1) = LUA_T_STRING;
tsvalue(S->top - 1) = ts;
*S->top++ = *oldvalue;
*S->top++ = newvalue;
luaD_callTM(im, 3, 0);
}
}
static void call_binTM(IMS event, const char *msg) {
TObject *im = luaT_getimbyObj(lua_state->stack.top - 2, event); // try first operand
if (ttype(im) == LUA_T_NIL) {
im = luaT_getimbyObj(lua_state->stack.top - 1, event); // try second operand
if (ttype(im) == LUA_T_NIL) {
im = luaT_getim(0, event); // try a 'global' i.m.
if (ttype(im) == LUA_T_NIL)
lua_error(msg);
}
}
lua_pushstring(luaT_eventname[event]);
luaD_callTM(im, 3, 1);
}
static void call_arith(IMS event) {
call_binTM(event, "unexpected type in arithmetic operation");
}
static void comparison(lua_Type ttype_less, lua_Type ttype_equal, lua_Type ttype_great, IMS op) {
Stack *S = &lua_state->stack;
TObject *l = S->top-2;
TObject *r = S->top-1;
int32 result;
if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER)
result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1;
else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING)
result = strcoll(svalue(l), svalue(r));
else {
call_binTM(op, "unexpected type in comparison");
return;
}
S->top--;
nvalue(S->top - 1) = 1;
ttype(S->top - 1) = (result < 0) ? ttype_less : (result == 0) ? ttype_equal : ttype_great;
}
void luaV_pack(StkId firstel, int32 nvararg, TObject *tab) {
TObject *firstelem = lua_state->stack.stack + firstel;
int32 i;
if (nvararg < 0)
nvararg = 0;
avalue(tab) = luaH_new(nvararg + 1); // +1 for field 'n'
ttype(tab) = LUA_T_ARRAY;
for (i = 0; i < nvararg; i++) {
TObject index;
ttype(&index) = LUA_T_NUMBER;
nvalue(&index) = (float)i + 1;
*(luaH_set(avalue(tab), &index)) = *(firstelem + i);
}
// store counter in field "n" */
{
TObject index, extra;
ttype(&index) = LUA_T_STRING;
tsvalue(&index) = luaS_new("n");
ttype(&extra) = LUA_T_NUMBER;
nvalue(&extra) = (float)nvararg;
*(luaH_set(avalue(tab), &index)) = extra;
}
}
static void adjust_varargs(StkId first_extra_arg) {
TObject arg;
luaV_pack(first_extra_arg, (lua_state->stack.top - lua_state->stack.stack) - first_extra_arg, &arg);
luaD_adjusttop(first_extra_arg);
*lua_state->stack.top++ = arg;
}
StkId luaV_execute(lua_Task *task) {
if (!task->executed) {
if (lua_callhook)
luaD_callHook(task->base, task->tf, 0);
luaD_checkstack((*task->pc++) + EXTRA_STACK);
if (*task->pc < ZEROVARARG) {
luaD_adjusttop(task->base + *(task->pc++));
} else {
luaC_checkGC();
adjust_varargs(task->base + (*task->pc++) - ZEROVARARG);
}
task->executed = true;
}
lua_state->callLevelCounter++;
while (1) {
switch ((OpCode)(task->aux = *task->pc++)) {
case PUSHNIL0:
ttype(task->S->top++) = LUA_T_NIL;
break;
case PUSHNIL:
task->aux = *task->pc++;
do {
ttype(task->S->top++) = LUA_T_NIL;
} while (task->aux--);
break;
case PUSHNUMBER:
task->aux = *task->pc++;
goto pushnumber;
case PUSHNUMBERW:
task->aux = next_word(task->pc);
goto pushnumber;
case PUSHNUMBER0:
case PUSHNUMBER1:
case PUSHNUMBER2:
task->aux -= PUSHNUMBER0;
pushnumber:
ttype(task->S->top) = LUA_T_NUMBER;
nvalue(task->S->top) = (float)task->aux;
task->S->top++;
break;
case PUSHLOCAL:
task->aux = *task->pc++;
goto pushlocal;
case PUSHLOCAL0:
case PUSHLOCAL1:
case PUSHLOCAL2:
case PUSHLOCAL3:
case PUSHLOCAL4:
case PUSHLOCAL5:
case PUSHLOCAL6:
case PUSHLOCAL7:
task->aux -= PUSHLOCAL0;
pushlocal:
*task->S->top++ = *((task->S->stack + task->base) + task->aux);
break;
case GETGLOBALW:
task->aux = next_word(task->pc);
goto getglobal;
case GETGLOBAL:
task->aux = *task->pc++;
goto getglobal;
case GETGLOBAL0:
case GETGLOBAL1:
case GETGLOBAL2:
case GETGLOBAL3:
case GETGLOBAL4:
case GETGLOBAL5:
case GETGLOBAL6:
case GETGLOBAL7:
task->aux -= GETGLOBAL0;
getglobal:
luaV_getglobal(tsvalue(&task->consts[task->aux]));
break;
case GETTABLE:
luaV_gettable();
break;
case GETDOTTEDW:
task->aux = next_word(task->pc); goto getdotted;
case GETDOTTED:
task->aux = *task->pc++;
goto getdotted;
case GETDOTTED0:
case GETDOTTED1:
case GETDOTTED2:
case GETDOTTED3:
case GETDOTTED4:
case GETDOTTED5:
case GETDOTTED6:
case GETDOTTED7:
task->aux -= GETDOTTED0;
getdotted:
*task->S->top++ = task->consts[task->aux];
luaV_gettable();
break;
case PUSHSELFW:
task->aux = next_word(task->pc);
goto pushself;
case PUSHSELF:
task->aux = *task->pc++;
goto pushself;
case PUSHSELF0:
case PUSHSELF1:
case PUSHSELF2:
case PUSHSELF3:
case PUSHSELF4:
case PUSHSELF5:
case PUSHSELF6:
case PUSHSELF7:
task->aux -= PUSHSELF0;
pushself:
{
TObject receiver = *(task->S->top - 1);
*task->S->top++ = task->consts[task->aux];
luaV_gettable();
*task->S->top++ = receiver;
break;
}
case PUSHCONSTANTW:
task->aux = next_word(task->pc);
goto pushconstant;
case PUSHCONSTANT:
task->aux = *task->pc++; goto pushconstant;
case PUSHCONSTANT0:
case PUSHCONSTANT1:
case PUSHCONSTANT2:
case PUSHCONSTANT3:
case PUSHCONSTANT4:
case PUSHCONSTANT5:
case PUSHCONSTANT6:
case PUSHCONSTANT7:
task->aux -= PUSHCONSTANT0;
pushconstant:
*task->S->top++ = task->consts[task->aux];
break;
case PUSHUPVALUE:
task->aux = *task->pc++;
goto pushupvalue;
case PUSHUPVALUE0:
case PUSHUPVALUE1:
task->aux -= PUSHUPVALUE0;
pushupvalue:
*task->S->top++ = task->cl->consts[task->aux + 1];
break;
case SETLOCAL:
task->aux = *task->pc++;
goto setlocal;
case SETLOCAL0:
case SETLOCAL1:
case SETLOCAL2:
case SETLOCAL3:
case SETLOCAL4:
case SETLOCAL5:
case SETLOCAL6:
case SETLOCAL7:
task->aux -= SETLOCAL0;
setlocal:
*((task->S->stack + task->base) + task->aux) = *(--task->S->top);
break;
case SETGLOBALW:
task->aux = next_word(task->pc);
goto setglobal;
case SETGLOBAL:
task->aux = *task->pc++;
goto setglobal;
case SETGLOBAL0:
case SETGLOBAL1:
case SETGLOBAL2:
case SETGLOBAL3:
case SETGLOBAL4:
case SETGLOBAL5:
case SETGLOBAL6:
case SETGLOBAL7:
task->aux -= SETGLOBAL0;
setglobal:
luaV_setglobal(tsvalue(&task->consts[task->aux]));
break;
case SETTABLE0:
luaV_settable(task->S->top - 3, 1);
break;
case SETTABLE:
luaV_settable(task->S->top - 3 - (*task->pc++), 2);
break;
case SETLISTW:
task->aux = next_word(task->pc);
task->aux *= LFIELDS_PER_FLUSH;
goto setlist;
case SETLIST:
task->aux = *(task->pc++) * LFIELDS_PER_FLUSH;
goto setlist;
case SETLIST0:
task->aux = 0;
setlist:
{
int32 n = *(task->pc++);
TObject *arr = task->S->top - n - 1;
for (; n; n--) {
ttype(task->S->top) = LUA_T_NUMBER;
nvalue(task->S->top) = (float)(n + task->aux);
*(luaH_set(avalue(arr), task->S->top)) = *(task->S->top - 1);
task->S->top--;
}
break;
}
case SETMAP0:
task->aux = 0;
goto setmap;
case SETMAP:
task->aux = *task->pc++;
setmap:
{
TObject *arr = task->S->top - (2 * task->aux) - 3;
do {
*(luaH_set(avalue(arr), task->S->top - 2)) = *(task->S->top - 1);
task->S->top -= 2;
} while (task->aux--);
break;
}
case POP:
task->aux = *task->pc++;
goto pop;
case POP0:
case POP1:
task->aux -= POP0;
pop:
task->S->top -= (task->aux + 1);
break;
case CREATEARRAYW:
task->aux = next_word(task->pc);
goto createarray;
case CREATEARRAY0:
case CREATEARRAY1:
task->aux -= CREATEARRAY0;
goto createarray;
case CREATEARRAY:
task->aux = *task->pc++;
createarray:
luaC_checkGC();
avalue(task->S->top) = luaH_new(task->aux);
ttype(task->S->top) = LUA_T_ARRAY;
task->S->top++;
break;
case EQOP:
case NEQOP:
{
int32 res = luaO_equalObj(task->S->top - 2, task->S->top - 1);
task->S->top--;
if (task->aux == NEQOP)
res = !res;
ttype(task->S->top - 1) = res ? LUA_T_NUMBER : LUA_T_NIL;
nvalue(task->S->top - 1) = 1;
break;
}
case LTOP:
comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT);
break;
case LEOP:
comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE);
break;
case GTOP:
comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT);
break;
case GEOP:
comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE);
break;
case ADDOP:
{
TObject *l = task->S->top - 2;
TObject *r = task->S->top - 1;
if (tonumber(r) || tonumber(l))
call_arith(IM_ADD);
else {
nvalue(l) += nvalue(r);
--task->S->top;
}
break;
}
case SUBOP:
{
TObject *l = task->S->top - 2;
TObject *r = task->S->top - 1;
if (tonumber(r) || tonumber(l))
call_arith(IM_SUB);
else {
nvalue(l) -= nvalue(r);
--task->S->top;
}
break;
}
case MULTOP:
{
TObject *l = task->S->top - 2;
TObject *r = task->S->top - 1;
if (tonumber(r) || tonumber(l))
call_arith(IM_MUL);
else {
nvalue(l) *= nvalue(r);
--task->S->top;
}
break;
}
case DIVOP:
{
TObject *l = task->S->top - 2;
TObject *r = task->S->top - 1;
if (tonumber(r) || tonumber(l))
call_arith(IM_DIV);
else {
nvalue(l) /= nvalue(r);
--task->S->top;
}
break;
}
case POWOP:
call_arith(IM_POW);
break;
case CONCOP:
{
TObject *l = task->S->top - 2;
TObject *r = task->S->top - 1;
if (tostring(l) || tostring(r))
call_binTM(IM_CONCAT, "unexpected type for concatenation");
else {
tsvalue(l) = strconc(svalue(l), svalue(r));
--task->S->top;
}
luaC_checkGC();
break;
}
case MINUSOP:
if (tonumber(task->S->top - 1)) {
ttype(task->S->top) = LUA_T_NIL;
task->S->top++;
call_arith(IM_UNM);
} else
nvalue(task->S->top - 1) = -nvalue(task->S->top - 1);
break;
case NOTOP:
ttype(task->S->top - 1) = (ttype(task->S->top - 1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL;
nvalue(task->S->top - 1) = 1;
break;
case ONTJMPW:
task->aux = next_word(task->pc);
goto ontjmp;
case ONTJMP:
task->aux = *task->pc++;
ontjmp:
if (ttype(task->S->top - 1) != LUA_T_NIL)
task->pc += task->aux;
else
task->S->top--;
break;
case ONFJMPW:
task->aux = next_word(task->pc);
goto onfjmp;
case ONFJMP:
task->aux = *task->pc++;
onfjmp:
if (ttype(task->S->top - 1) == LUA_T_NIL)
task->pc += task->aux;
else
task->S->top--;
break;
case JMPW:
task->aux = next_word(task->pc);
goto jmp;
case JMP:
task->aux = *task->pc++;
jmp:
task->pc += task->aux;
break;
case IFFJMPW:
task->aux = next_word(task->pc);
goto iffjmp;
case IFFJMP:
task->aux = *task->pc++;
iffjmp:
if (ttype(--task->S->top) == LUA_T_NIL)
task->pc += task->aux;
break;
case IFTUPJMPW:
task->aux = next_word(task->pc);
goto iftupjmp;
case IFTUPJMP:
task->aux = *task->pc++;
iftupjmp:
if (ttype(--task->S->top) != LUA_T_NIL)
task->pc -= task->aux;
break;
case IFFUPJMPW:
task->aux = next_word(task->pc);
goto iffupjmp;
case IFFUPJMP:
task->aux = *task->pc++;
iffupjmp:
if (ttype(--task->S->top) == LUA_T_NIL)
task->pc -= task->aux;
break;
case CLOSURE:
task->aux = *task->pc++;
goto closure;
case CLOSURE0:
case CLOSURE1:
task->aux -= CLOSURE0;
closure:
luaV_closure(task->aux);
luaC_checkGC();
break;
case CALLFUNC:
task->aux = *task->pc++;
goto callfunc;
case CALLFUNC0:
case CALLFUNC1:
task->aux -= CALLFUNC0;
callfunc:
lua_state->callLevelCounter--;
return -((task->S->top - task->S->stack) - (*task->pc++));
case ENDCODE:
task->S->top = task->S->stack + task->base;
// fall through
case RETCODE:
if (lua_callhook)
luaD_callHook(task->base, nullptr, 1);
lua_state->callLevelCounter--;
return (task->base + ((task->aux == RETCODE) ? *task->pc : 0));
case SETLINEW:
task->aux = next_word(task->pc);
goto setline;
case SETLINE:
task->aux = *task->pc++;
setline:
if ((task->S->stack + task->base - 1)->ttype != LUA_T_LINE) {
// open space for LINE value */
luaD_openstack((task->S->top - task->S->stack) - task->base);
task->base++;
(task->S->stack + task->base - 1)->ttype = LUA_T_LINE;
}
(task->S->stack + task->base - 1)->value.i = task->aux;
if (lua_linehook)
luaD_lineHook(task->aux);
break;
#ifdef LUA_DEBUG
default:
LUA_INTERNALERROR("internal error - opcode doesn't match");
#endif
}
}
}
} // end of namespace Grim

30
engines/grim/lua/lvm.h Normal file
View File

@@ -0,0 +1,30 @@
/*
** Lua virtual machine
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LVM_H
#define GRIM_LVM_H
#include "engines/grim/lua/ldo.h"
#include "engines/grim/lua/lobject.h"
namespace Grim {
#define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (luaV_tonumber(o) != 0))
#define tostring(o) ((ttype(o) != LUA_T_STRING) && (luaV_tostring(o) != 0))
void luaV_pack(StkId firstel, int32 nvararg, TObject *tab);
int32 luaV_tonumber(TObject *obj);
int32 luaV_tostring(TObject *obj);
void luaV_gettable();
void luaV_settable(TObject *t, int32 mode);
void luaV_getglobal(TaggedString *ts);
void luaV_setglobal(TaggedString *ts);
void luaV_closure(int32 nelems);
} // end of namespace Grim
#endif

42
engines/grim/lua/lzio.cpp Normal file
View File

@@ -0,0 +1,42 @@
/*
** a generic input stream interface
** See Copyright Notice in lua.h
*/
#include "engines/grim/lua/lzio.h"
#include "common/file.h"
namespace Grim {
int32 zgeteoz(ZIO *) {
return EOZ;
}
ZIO *zopen(ZIO *z, const char *b, int32 size, const char *name) {
if (!b)
return nullptr;
z->n = size;
z->p = (const byte *)b;
z->name = name;
return z;
}
int32 zread (ZIO *z, void *b, int32 n) {
while (n) {
int32 m;
if (z->n == 0) {
return n;
}
m = (n <= z->n) ? n : z->n;
memcpy(b, z->p, m);
z->n -= m;
z->p += m;
b = (char *)b + m;
n -= m;
}
return 0;
}
} // end of namespace Grim

47
engines/grim/lua/lzio.h Normal file
View File

@@ -0,0 +1,47 @@
/*
** Buffered streams
** See Copyright Notice in lua.h
*/
#ifndef GRIM_LZIO_H
#define GRIM_LZIO_H
#include "common/scummsys.h"
namespace Common {
class File;
}
namespace Grim {
// For Lua only
#define zopen luaZ_mopen
#define EOZ (-1) // end of stream
typedef struct zio ZIO;
ZIO *zopen(ZIO *z, const char *b, int32 size, const char *name);
int32 zread(ZIO *z, void *b, int32 n); // read next n bytes
int32 zgeteoz(ZIO *);
#define zgetc(z) (--(z)->n >= 0 ? ((int32)*(z)->p++): zgeteoz(z))
#define zungetc(z) (++(z)->n, --(z)->p)
#define zname(z) ((z)->name)
// --------- Private Part ------------------
#define ZBSIZE 256 // buffer size
struct zio {
int32 n; // bytes still unread
const byte *p; // current position in buffer
const char *name;
byte buffer[ZBSIZE]; // buffer
};
} // end of namespace Grim
#endif