123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- #include "golua.h"
- GoInterface golua_idtointerface(unsigned int);
- GoInterface golua_cfunctiontointerface(lua_CFunction);
- GoUintptr golua_callallocf(GoUintptr,GoUintptr,size_t,size_t);
- #define MT_GOFUNCTION "GoLua.GoFunction"
- #define MT_GOINTERFACE "GoLua.GoInterface"
- #define GOLUA_DEFAULT_MSGHANDLER "golua_default_msghandler"
- static const char GoStateRegistryKey = 'k'; //golua registry key
- static const char PanicFIDRegistryKey = 'k';
- /* taken from lua5.2 source */
- void *testudata(lua_State *L, int ud, const char *tname)
- {
- void *p = lua_touserdata(L, ud);
- if (p != NULL)
- { /* value is a userdata? */
- if (lua_getmetatable(L, ud))
- { /* does it have a metatable? */
- luaL_getmetatable(L, tname); /* get correct metatable */
- if (!lua_rawequal(L, -1, -2)) /* not the same? */
- p = NULL; /* value is a userdata with wrong metatable */
- lua_pop(L, 2); /* remove both metatables */
- return p;
- }
- }
- return NULL; /* value is not a userdata with a metatable */
- }
- int clua_isgofunction(lua_State *L, int n)
- {
- return testudata(L, n, MT_GOFUNCTION) != NULL;
- }
- int clua_isgostruct(lua_State *L, int n)
- {
- return testudata(L, n, MT_GOINTERFACE) != NULL;
- }
- unsigned int* clua_checkgosomething(lua_State* L, int index, const char *desired_metatable)
- {
- if (desired_metatable != NULL)
- {
- return testudata(L, index, desired_metatable);
- }
- else
- {
- unsigned int *sid = testudata(L, index, MT_GOFUNCTION);
- if (sid != NULL) return sid;
- return testudata(L, index, MT_GOINTERFACE);
- }
- }
- size_t clua_getgostate(lua_State* L)
- {
- size_t gostateindex;
- //get gostate from registry entry
- lua_pushlightuserdata(L,(void*)&GoStateRegistryKey);
- lua_gettable(L, LUA_REGISTRYINDEX);
- gostateindex = (size_t)lua_touserdata(L,-1);
- lua_pop(L,1);
- return gostateindex;
- }
- //wrapper for callgofunction
- int callback_function(lua_State* L)
- {
- int r;
- unsigned int *fid = clua_checkgosomething(L, 1, MT_GOFUNCTION);
- size_t gostateindex = clua_getgostate(L);
- //remove the go function from the stack (to present same behavior as lua_CFunctions)
- lua_remove(L,1);
- return golua_callgofunction(gostateindex, fid!=NULL ? *fid : -1);
- }
- //wrapper for gchook
- int gchook_wrapper(lua_State* L)
- {
- //printf("Garbage collection wrapper\n");
- unsigned int* fid = clua_checkgosomething(L, -1, NULL);
- size_t gostateindex = clua_getgostate(L);
- if (fid != NULL)
- return golua_gchook(gostateindex,*fid);
- return 0;
- }
- unsigned int clua_togofunction(lua_State* L, int index)
- {
- unsigned int *r = clua_checkgosomething(L, index, MT_GOFUNCTION);
- return (r != NULL) ? *r : -1;
- }
- unsigned int clua_togostruct(lua_State *L, int index)
- {
- unsigned int *r = clua_checkgosomething(L, index, MT_GOINTERFACE);
- return (r != NULL) ? *r : -1;
- }
- void clua_pushgofunction(lua_State* L, unsigned int fid)
- {
- unsigned int* fidptr = (unsigned int *)lua_newuserdata(L, sizeof(unsigned int));
- *fidptr = fid;
- luaL_getmetatable(L, MT_GOFUNCTION);
- lua_setmetatable(L, -2);
- }
- static int callback_c (lua_State* L)
- {
- int fid = clua_togofunction(L,lua_upvalueindex(1));
- size_t gostateindex = clua_getgostate(L);
- return golua_callgofunction(gostateindex,fid);
- }
- void clua_pushcallback(lua_State* L)
- {
- lua_pushcclosure(L,callback_c,1);
- }
- void clua_pushgostruct(lua_State* L, unsigned int iid)
- {
- unsigned int* iidptr = (unsigned int *)lua_newuserdata(L, sizeof(unsigned int));
- *iidptr = iid;
- luaL_getmetatable(L, MT_GOINTERFACE);
- lua_setmetatable(L,-2);
- }
- int default_panicf(lua_State *L)
- {
- const char *s = lua_tostring(L, -1);
- printf("Lua unprotected panic: %s\n", s);
- abort();
- }
- void clua_setgostate(lua_State* L, size_t gostateindex)
- {
- lua_atpanic(L, default_panicf);
- lua_pushlightuserdata(L,(void*)&GoStateRegistryKey);
- lua_pushlightuserdata(L, (void*)gostateindex);
- //set into registry table
- lua_settable(L, LUA_REGISTRYINDEX);
- }
- /* called when lua code attempts to access a field of a published go object */
- int interface_index_callback(lua_State *L)
- {
- unsigned int *iid = clua_checkgosomething(L, 1, MT_GOINTERFACE);
- if (iid == NULL)
- {
- lua_pushnil(L);
- return 1;
- }
- char *field_name = (char *)lua_tostring(L, 2);
- if (field_name == NULL)
- {
- lua_pushnil(L);
- return 1;
- }
- size_t gostateindex = clua_getgostate(L);
- int r = golua_interface_index_callback(gostateindex, *iid, field_name);
- if (r < 0)
- {
- lua_error(L);
- return 0;
- }
- else
- {
- return r;
- }
- }
- /* called when lua code attempts to set a field of a published go object */
- int interface_newindex_callback(lua_State *L)
- {
- unsigned int *iid = clua_checkgosomething(L, 1, MT_GOINTERFACE);
- if (iid == NULL)
- {
- lua_pushnil(L);
- return 1;
- }
- char *field_name = (char *)lua_tostring(L, 2);
- if (field_name == NULL)
- {
- lua_pushnil(L);
- return 1;
- }
- size_t gostateindex = clua_getgostate(L);
- int r = golua_interface_newindex_callback(gostateindex, *iid, field_name);
- if (r < 0)
- {
- lua_error(L);
- return 0;
- }
- else
- {
- return r;
- }
- }
- int panic_msghandler(lua_State *L)
- {
- size_t gostateindex = clua_getgostate(L);
- go_panic_msghandler(gostateindex, (char *)lua_tolstring(L, -1, NULL));
- return 0;
- }
- void clua_hide_pcall(lua_State *L)
- {
- lua_getglobal(L, "pcall");
- lua_setglobal(L, "unsafe_pcall");
- lua_pushnil(L);
- lua_setglobal(L, "pcall");
- lua_getglobal(L, "xpcall");
- lua_setglobal(L, "unsafe_xpcall");
- lua_pushnil(L);
- lua_setglobal(L, "xpcall");
- }
- void clua_initstate(lua_State* L)
- {
- /* create the GoLua.GoFunction metatable */
- luaL_newmetatable(L, MT_GOFUNCTION);
- // gofunction_metatable[__call] = &callback_function
- lua_pushliteral(L,"__call");
- lua_pushcfunction(L,&callback_function);
- lua_settable(L,-3);
- // gofunction_metatable[__gc] = &gchook_wrapper
- lua_pushliteral(L,"__gc");
- lua_pushcfunction(L,&gchook_wrapper);
- lua_settable(L,-3);
- lua_pop(L,1);
- luaL_newmetatable(L, MT_GOINTERFACE);
- // gointerface_metatable[__gc] = &gchook_wrapper
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, &gchook_wrapper);
- lua_settable(L, -3);
- // gointerface_metatable[__index] = &interface_index_callback
- lua_pushliteral(L, "__index");
- lua_pushcfunction(L, &interface_index_callback);
- lua_settable(L, -3);
- // gointerface_metatable[__newindex] = &interface_newindex_callback
- lua_pushliteral(L, "__newindex");
- lua_pushcfunction(L, &interface_newindex_callback);
- lua_settable(L, -3);
- lua_register(L, GOLUA_DEFAULT_MSGHANDLER, &panic_msghandler);
- lua_pop(L, 1);
- }
- int callback_panicf(lua_State* L)
- {
- lua_pushlightuserdata(L,(void*)&PanicFIDRegistryKey);
- lua_gettable(L,LUA_REGISTRYINDEX);
- unsigned int fid = lua_tointeger(L,-1);
- lua_pop(L,1);
- size_t gostateindex = clua_getgostate(L);
- return golua_callpanicfunction(gostateindex,fid);
- }
- //TODO: currently setting garbage when panicf set to null
- GoInterface clua_atpanic(lua_State* L, unsigned int panicf_id)
- {
- //get old panicfid
- unsigned int old_id;
- lua_pushlightuserdata(L, (void*)&PanicFIDRegistryKey);
- lua_gettable(L,LUA_REGISTRYINDEX);
- if(lua_isnil(L, -1) == 0)
- old_id = lua_tointeger(L,-1);
- lua_pop(L, 1);
- //set registry key for function id of go panic function
- lua_pushlightuserdata(L, (void*)&PanicFIDRegistryKey);
- //push id value
- lua_pushinteger(L, panicf_id);
- //set into registry table
- lua_settable(L, LUA_REGISTRYINDEX);
- //now set the panic function
- lua_CFunction pf = lua_atpanic(L,&callback_panicf);
- //make a GoInterface with a wrapped C panicf or the original go panicf
- if(pf == &callback_panicf)
- {
- return golua_idtointerface(old_id);
- }
- else
- {
- //TODO: technically UB, function ptr -> non function ptr
- return golua_cfunctiontointerface((GoUintptr *)pf);
- }
- }
- int clua_callluacfunc(lua_State* L, lua_CFunction f)
- {
- return f(L);
- }
- void* allocwrapper(void* ud, void *ptr, size_t osize, size_t nsize)
- {
- return (void*)golua_callallocf((GoUintptr)ud,(GoUintptr)ptr,osize,nsize);
- }
- lua_State* clua_newstate(void* goallocf)
- {
- return lua_newstate(&allocwrapper,goallocf);
- }
- void clua_setallocf(lua_State* L, void* goallocf)
- {
- lua_setallocf(L,&allocwrapper,goallocf);
- }
- void clua_openbase(lua_State* L)
- {
- lua_pushcfunction(L,&luaopen_base);
- lua_pushstring(L,"");
- lua_call(L, 1, 0);
- clua_hide_pcall(L);
- }
- void clua_hook_function(lua_State *L, lua_Debug *ar)
- {
- lua_checkstack(L, 2);
- size_t gostateindex = clua_getgostate(L);
- golua_callgohook(gostateindex);
- }
- void clua_sethook(lua_State* L, int n)
- {
- lua_sethook(L, &clua_hook_function, LUA_MASKCOUNT, n);
- }
|