lua_t* lua_allocate(void) { lua_t* env = memory_allocate(HASH_LUA, sizeof(lua_t), 0, MEMORY_PERSISTENT | MEMORY_32BIT_ADDRESS | MEMORY_ZERO_INITIALIZED); //Foundation allocators can meet demands of luajit on both 32 and 64 bit platforms lua_State* state = lua_newstate(lua_allocator, env); if (!state) { log_error(HASH_LUA, ERROR_INTERNAL_FAILURE, STRING_CONST("Unable to allocate Lua state")); memory_deallocate(env); return 0; } lua_atpanic(state, lua_panic); //Disable automagic gc lua_gc(state, LUA_GCCOLLECT, 0); lua_pushlightuserdata(state, env); lua_setlglobal(state, "__environment", 13); env->state = state; env->calldepth = 0; #if BUILD_ENABLE_LUA_THREAD_SAFE semaphore_initialize(&env->execution_right, 1); env->queue_head = 0; atomic_store32(&env->queue_tail, 0); #endif int stacksize = lua_gettop(state); luaL_openlibs(state); lua_module_registry_initialize(state); lua_pop(state, lua_gettop(state) - stacksize); return env; }
static void lua_push_method_global(lua_State* state, const char* name, size_t length, lua_CFunction fn) { lua_pushcclosure(state, fn, 0); lua_setlglobal(state, name, length); }
static void lua_push_integer_global(lua_State* state, const char* name, size_t length, int value) { lua_pushinteger(state, value); lua_setlglobal(state, name, length); }
static void lua_push_number_global(lua_State* state, const char* name, size_t length, real value) { lua_pushnumber(state, value); lua_setlglobal(state, name, length); }
lua_result_t lua_do_bind(lua_t* env, const char* property, size_t length, lua_command_t cmd, lua_value_t val) { lua_State* state; int stacksize; size_t start, next; string_const_t part; if (!env || !length) return LUA_ERROR; state = env->state; stacksize = lua_gettop(state); next = string_find(property, length, '.', 0); if (next != STRING_NPOS) { int tables; unsigned int numtables = 0; part = string_const(property, next); lua_getlglobal(state, part.str, part.length); if (lua_isnil(state, -1)) { //Create global table lua_pop(state, 1); lua_newtable(state); lua_pushvalue(state, -1); lua_setlglobal(state, part.str, part.length); log_debugf(HASH_LUA, STRING_CONST("Created global table: %.*s"), STRING_FORMAT(part)); } else if (!lua_istable(state, -1)) { log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script bind call, existing data '%.*s' in '%.*s' is not a table"), STRING_FORMAT(part), (int)length, property); lua_pop(state, lua_gettop(state) - stacksize); return LUA_ERROR; } //Top of stack is now table FOUNDATION_ASSERT(lua_istable(state, -1)); ++next; start = next; ++numtables; next = string_find(property, length, '.', next); while (next != STRING_NPOS) { part = string_const(property + start, next - start); lua_pushlstring(state, part.str, part.length); lua_gettable(state, -2); if (lua_isnil(state, -1)) { //Create sub-table lua_pop(state, 1); lua_newtable(state); lua_pushlstring(state, part.str, part.length); lua_pushvalue(state, -2); lua_settable(state, -4); log_debugf(HASH_LUA, STRING_CONST("Created table: %.*s"), next, property); } else if (!lua_istable(state, -1)) { log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script bind call, existing data '%.*s' in '%.*s' is not a table"), STRING_FORMAT(part), (int)next, property); lua_pop(state, lua_gettop(state) - stacksize); return LUA_ERROR; } //Top of stack is now table FOUNDATION_ASSERT(lua_istable(state, -1)); ++next; start = next; next = string_find(property, length, '.', next); ++numtables; } part = string_const(property + start, length - start); switch (cmd) { case LUACMD_BIND: lua_push_method(state, STRING_ARGS(part), val.fn); break; case LUACMD_BIND_INT: lua_push_integer(state, STRING_ARGS(part), val.ival); break; case LUACMD_BIND_VAL: lua_push_number(state, STRING_ARGS(part), val.val); break; default: break; } tables = lua_gettop(state) - stacksize; lua_pop(state, tables); FOUNDATION_ASSERT(tables == (int)numtables); } else { part = string_const(property, length); switch (cmd) { case LUACMD_BIND: lua_push_method_global(state, STRING_ARGS(part), val.fn); break; case LUACMD_BIND_INT: lua_push_integer_global(state, STRING_ARGS(part), val.ival); break; case LUACMD_BIND_VAL: lua_push_number_global(state, STRING_ARGS(part), val.val); break; default: break; } } return LUA_OK; }