179 lines
5.5 KiB
C
179 lines
5.5 KiB
C
typedef lua_State lua;
|
|
|
|
// the Lua interpreter
|
|
static lua *L;
|
|
|
|
#if is(linux)
|
|
void luaopen_libv4k(lua_State *L) {}
|
|
#endif
|
|
|
|
static void* script__realloc(void *userdef, void *ptr, size_t osize, size_t nsize) {
|
|
(void)userdef;
|
|
return ptr = REALLOC( ptr, /* (osize+1) * */ nsize );
|
|
}
|
|
static int script__traceback(lua_State *L) {
|
|
if (!lua_isstring(L, 1)) { // try metamethod if non-string error object
|
|
if (lua_isnoneornil(L, 1) ||
|
|
!luaL_callmeta(L, 1, "__tostring") ||
|
|
!lua_isstring(L, -1))
|
|
return 1; // return non-string error object
|
|
lua_remove(L, 1); // replace object with result of __tostring metamethod
|
|
}
|
|
luaL_traceback(L, L, lua_tostring(L, 1), 1);
|
|
return 1;
|
|
}
|
|
static void script__error(lua_State *L, int status) {
|
|
if (status != 0) {
|
|
const char *errormsg = lua_tostring(L, -1);
|
|
PRINTF( "!-- %s\n", errormsg);
|
|
lua_pop(L, 1); // remove error message
|
|
}
|
|
}
|
|
static int script__call(lua_State *L, int narg, int clear) {
|
|
#if ENABLE_FASTCALL_LUA
|
|
lua_call(L, 0, 0);
|
|
return 0;
|
|
#else
|
|
int base = lua_gettop(L) - narg; // function index
|
|
lua_pushcfunction(L, script__traceback); // push traceback function
|
|
lua_insert(L, base); // put it under chunk and args
|
|
int status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
|
|
script__error(L, status);
|
|
lua_remove(L, base); // remove traceback function
|
|
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); // force gc in case of errors
|
|
return status;
|
|
#endif
|
|
}
|
|
|
|
void script_bind_function(const char *c_name, void *c_function) {
|
|
lua_pushcfunction( L, c_function );
|
|
lua_setglobal( L, c_name );
|
|
}
|
|
|
|
void script_call(const char *lua_function) {
|
|
lua_getglobal( L, lua_function );
|
|
script__call( L, 0, 1 );
|
|
}
|
|
|
|
void script_bind_class(const char *classname, int num, const char **methods, void **functions) {
|
|
lua_newtable( L );
|
|
|
|
for( int i = 0; i < num; ++i) {
|
|
lua_pushcfunction( L, functions[i] );
|
|
lua_setfield( L, 1, methods[i] );
|
|
}
|
|
|
|
lua_setglobal( L, classname );
|
|
}
|
|
|
|
void script_run(const char *script) {
|
|
int ret = luaL_dostring(L, script);
|
|
if( ret != LUA_OK ) {
|
|
PRINTF("!Script failed to run: %s\n", lua_tostring(L, -1));
|
|
lua_pop(L, 1); // pop error message
|
|
}
|
|
}
|
|
|
|
void script_runfile(const char *pathfile) {
|
|
PRINTF( "Loading script '%s'\n", pathfile );
|
|
int loadResult = luaL_loadfile( L, pathfile );
|
|
|
|
/**/ if( loadResult == LUA_OK ) {
|
|
script__call( L, 0, 1 );
|
|
}
|
|
else if( loadResult == LUA_ERRSYNTAX ) {
|
|
PRINTF("!Script failed to load (LUA_ERRSYNTAX, '%s'): %s\n", lua_tostring( L, 1 ), pathfile );
|
|
// lua_pop(L, 1); // pop error message
|
|
}
|
|
else if( loadResult == LUA_ERRMEM ) {
|
|
PRINTF("!Script failed to load (LUA_ERRMEM): %s\n", pathfile);
|
|
}
|
|
else {
|
|
PRINTF("!Script failed to load: %s\n", pathfile );
|
|
}
|
|
}
|
|
|
|
// syntax sugars
|
|
/* usage:
|
|
int window_create_lua(lua *L) {
|
|
window_create(arg_float(1), arg_int(2));
|
|
return_void(0);
|
|
}
|
|
int window_swap_lua(lua *L) {
|
|
int r = window_swap();
|
|
return_int(r);
|
|
}
|
|
*/
|
|
|
|
#define arg_int(nth) lua_tointeger(L, nth)
|
|
#define arg_bool(nth) lua_toboolean(L, nth)
|
|
#define arg__Bool(nth) lua_toboolean(L, nth)
|
|
#define arg_float(nth) (float)lua_tonumber(L, nth)
|
|
#define arg_double(nth) lua_tonumber(L, nth)
|
|
#define arg_string(nth) lua_tolstring(L, nth, 0)
|
|
#define return_void(x) return ((x), 0)
|
|
#define return_bool(x) return (lua_pushboolean(L, x), 1)
|
|
#define return__Bool(x) return (lua_pushboolean(L, x), 1)
|
|
#define return_int(x) return (lua_pushinteger(L, x), 1)
|
|
#define return_float(x) return (lua_pushnumber(L, x), 1)
|
|
#define return_double(x) return (lua_pushnumber(L, x), 1)
|
|
#define return_string(x) return (lua_pushstring(L, x), 1)
|
|
|
|
#define WRAP_ALL(...) EXPAND(WRAP_ALL, __VA_ARGS__)
|
|
#define WRAP_ALL2(rc, func) int func##_lua(lua*L) { return_##rc(func()); }
|
|
#define WRAP_ALL3(rc, func, a1) int func##_lua(lua*L) { return_##rc(func(arg_##a1(1))); }
|
|
#define WRAP_ALL4(rc, func, a1,a2) int func##_lua(lua*L) { return_##rc(func(arg_##a1(1),arg_##a2(2))); }
|
|
|
|
#define BIND_ALL(...) EXPAND(BIND_ALL, __VA_ARGS__);
|
|
#define BIND_ALL2(rc,func) script_bind_function(#func, func##_lua)
|
|
#define BIND_ALL3(rc,func,a1) script_bind_function(#func, func##_lua)
|
|
#define BIND_ALL4(rc,func,a1,a2) script_bind_function(#func, func##_lua)
|
|
|
|
#define XMACRO(X) /* @fixme: add all remaining V4K functions */ \
|
|
X(bool, window_create, float, int ) \
|
|
X(bool, window_swap ) \
|
|
X(void, ddraw_grid, float ) \
|
|
X(bool, ui_panel, string, int ) \
|
|
X(bool, ui_notify, string, string ) \
|
|
X(void, ui_panel_end )
|
|
|
|
XMACRO(WRAP_ALL)
|
|
|
|
void script_quit(void) {
|
|
if( L ) {
|
|
lua_close(L);
|
|
L = 0;
|
|
}
|
|
}
|
|
void script_init() {
|
|
if( !L ) {
|
|
// v4k_init();
|
|
|
|
// initialize Lua
|
|
L = lua_newstate(script__realloc, 0); // L = luaL_newstate();
|
|
|
|
// load various Lua libraries
|
|
luaL_openlibs(L);
|
|
luaopen_base(L);
|
|
luaopen_table(L);
|
|
luaopen_io(L);
|
|
luaopen_string(L);
|
|
luaopen_math(L);
|
|
|
|
// @fixme: workaround that prevents script binding on lua 5.4.3 on top of luajit 2.1.0-beta3 on linux. lua_setglobal() crashing when accessing null L->l_G
|
|
if(L->l_G) {
|
|
XMACRO(BIND_ALL);
|
|
}
|
|
|
|
atexit(script_quit);
|
|
}
|
|
}
|
|
|
|
bool script_tests() {
|
|
// script test (lua)
|
|
script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" );
|
|
return true;
|
|
}
|
|
|
|
#undef XMACRO
|