Initial commit
This commit is contained in:
14
engines/grim/lua/Changelog
Normal file
14
engines/grim/lua/Changelog
Normal 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
505
engines/grim/lua/lapi.cpp
Normal 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
23
engines/grim/lua/lapi.h
Normal 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
|
||||
107
engines/grim/lua/lauxlib.cpp
Normal file
107
engines/grim/lua/lauxlib.cpp
Normal 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
|
||||
51
engines/grim/lua/lauxlib.h
Normal file
51
engines/grim/lua/lauxlib.h
Normal 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
|
||||
66
engines/grim/lua/lbuffer.cpp
Normal file
66
engines/grim/lua/lbuffer.cpp
Normal 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
|
||||
531
engines/grim/lua/lbuiltin.cpp
Normal file
531
engines/grim/lua/lbuiltin.cpp
Normal 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
|
||||
24
engines/grim/lua/lbuiltin.h
Normal file
24
engines/grim/lua/lbuiltin.h
Normal 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
450
engines/grim/lua/ldo.cpp
Normal 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
45
engines/grim/lua/ldo.h
Normal 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
|
||||
87
engines/grim/lua/lfunc.cpp
Normal file
87
engines/grim/lua/lfunc.cpp
Normal 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
23
engines/grim/lua/lfunc.h
Normal 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
259
engines/grim/lua/lgc.cpp
Normal 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
22
engines/grim/lua/lgc.h
Normal 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
466
engines/grim/lua/liolib.cpp
Normal 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
446
engines/grim/lua/llex.cpp
Normal 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
40
engines/grim/lua/llex.h
Normal 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
|
||||
153
engines/grim/lua/lmathlib.cpp
Normal file
153
engines/grim/lua/lmathlib.cpp
Normal 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
90
engines/grim/lua/lmem.cpp
Normal 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
38
engines/grim/lua/lmem.h
Normal 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
|
||||
|
||||
84
engines/grim/lua/lobject.cpp
Normal file
84
engines/grim/lua/lobject.cpp
Normal 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
154
engines/grim/lua/lobject.h
Normal 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
180
engines/grim/lua/lopcodes.h
Normal 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
|
||||
21
engines/grim/lua/lparser.h
Normal file
21
engines/grim/lua/lparser.h
Normal 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
|
||||
584
engines/grim/lua/lrestore.cpp
Normal file
584
engines/grim/lua/lrestore.cpp
Normal 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
386
engines/grim/lua/lsave.cpp
Normal 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
258
engines/grim/lua/lstate.cpp
Normal 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
121
engines/grim/lua/lstate.h
Normal 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
|
||||
231
engines/grim/lua/lstring.cpp
Normal file
231
engines/grim/lua/lstring.cpp
Normal 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
|
||||
31
engines/grim/lua/lstring.h
Normal file
31
engines/grim/lua/lstring.h
Normal 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
|
||||
503
engines/grim/lua/lstrlib.cpp
Normal file
503
engines/grim/lua/lstrlib.cpp
Normal 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
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
49
engines/grim/lua/lstx.h
Normal 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
205
engines/grim/lua/ltable.cpp
Normal 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
28
engines/grim/lua/ltable.h
Normal 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
380
engines/grim/lua/ltask.cpp
Normal 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
35
engines/grim/lua/ltask.h
Normal 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
248
engines/grim/lua/ltm.cpp
Normal 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
62
engines/grim/lua/ltm.h
Normal 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
219
engines/grim/lua/lua.h
Normal 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
|
||||
35
engines/grim/lua/luadebug.h
Normal file
35
engines/grim/lua/luadebug.h
Normal 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
32
engines/grim/lua/lualib.h
Normal 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
|
||||
|
||||
187
engines/grim/lua/lundump.cpp
Normal file
187
engines/grim/lua/lundump.cpp
Normal 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
|
||||
32
engines/grim/lua/lundump.h
Normal file
32
engines/grim/lua/lundump.h
Normal 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
695
engines/grim/lua/lvm.cpp
Normal 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
30
engines/grim/lua/lvm.h
Normal 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
42
engines/grim/lua/lzio.cpp
Normal 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
47
engines/grim/lua/lzio.h
Normal 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
|
||||
Reference in New Issue
Block a user