static lua_result_t lua_do_call_custom(lua_t* env, const char* method, size_t length, lua_arg_t* arg) { lua_State* state; lua_result_t result; int numargs, i; int stacksize; size_t start, next; string_const_t part; state = env->state; stacksize = lua_gettop(state); result = LUA_OK; ++env->calldepth; next = string_find(method, length, '.', 0); if (next != STRING_NPOS) { part = string_const(method, next); lua_getlglobal(state, part.str, part.length); if (lua_isnil(state, -1)) { log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script call, '%.*s' is not set (%.*s)"), STRING_FORMAT(part), (int)length, method); --env->calldepth; lua_pop(state, lua_gettop(state) - stacksize); return LUA_ERROR; } else if (!lua_istable(state, -1)) { log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script call, existing data '%.*s' in '%.*s' is not a table"), STRING_FORMAT(part), (int)length, method); --env->calldepth; 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(method, length, '.', next); while (next != STRING_NPOS) { part = string_const(method + start, next - start); lua_pushlstring(state, part.str, part.length); lua_gettable(state, -2); if (lua_isnil(state, -1)) { log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script call, '%.*s' is not set (%.*s)"), STRING_FORMAT(part), (int)next, method); --env->calldepth; lua_pop(state, lua_gettop(state) - stacksize); return LUA_ERROR; } else if (!lua_istable(state, -1)) { log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script call, existing data '%.*s' in '%.*s' is not a table"), STRING_FORMAT(part), (int)next, method); --env->calldepth; 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(method, length, '.', next); } part = string_const(method + start, length - start); lua_pushlstring(state, part.str, part.length); lua_gettable(state, -2); } else { lua_getlglobal(state, method, length); } if (lua_isnil(state, -1)) { --env->calldepth; lua_pop(state, lua_gettop(state) - stacksize); //Method does not exist in Lua context log_errorf(HASH_LUA, ERROR_INVALID_VALUE, STRING_CONST("Invalid script call, '%.*s' is not a function"), (int)length, method); return LUA_ERROR; } numargs = 0; if (arg) { numargs = (arg->num < LUA_MAX_ARGS) ? arg->num : LUA_MAX_ARGS; for (i = 0; i < numargs; ++i) { switch (arg->type[i]) { case LUADATA_PTR: lua_pushlightuserdata(state, arg->value[i].ptr); break; case LUADATA_OBJ: lua_pushobject(state, arg->value[i].obj); break; case LUADATA_INT: lua_pushinteger(state, arg->value[i].ival); break; case LUADATA_REAL: lua_pushnumber(state, arg->value[i].val); break; case LUADATA_STR: lua_pushlstring(state, arg->value[i].str, arg->size[i]); break; case LUADATA_BOOL: lua_pushboolean(state, arg->value[i].flag); break; case LUADATA_INTARR: { const int* values = arg->value[i].ptr; lua_newtable(state); for (uint16_t ia = 0; ia < arg->size[i]; ++ia) { lua_pushinteger(state, ia + 1); lua_pushinteger(state, values[ia]); lua_settable(state, -3); } break; } case LUADATA_REALARR: { const real* values = arg->value[i].ptr; lua_newtable(state); for (uint16_t ia = 0; ia < arg->size[i]; ++ia) { lua_pushinteger(state, ia + 1); lua_pushnumber(state, values[ia]); lua_settable(state, -3); } break; } default: --numargs; break; } } } //TODO: Parse return value from call if (lua_pcall(state, numargs, 0, 0) != 0) { string_const_t errmsg = {0, 0}; errmsg.str = lua_tolstring(state, -1, &errmsg.length); log_errorf(HASH_LUA, ERROR_INTERNAL_FAILURE, STRING_CONST("Calling %.*s : %.*s"), (int)length, method, STRING_FORMAT(errmsg)); result = LUA_ERROR; } --env->calldepth; lua_pop(state, lua_gettop(state) - stacksize); return result; }
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; }