#include "lua_runner.hpp" #include #include extern "C" { #include #include "errors.h" } Lua_runner::Lua_runner(const char *path) { this->L =NULL; this->L = luaL_newstate(); errno = 0;//清除老错误信息 if(this->L == NULL){ errno = LUAERR_LUA_STATE; return ; } luaL_openlibs(this->L);//创建lua状态机,打开标准库 const char* save_stdlib_code = "local std = {} " "for k, v in pairs(_G) do std[k] = true end " "_G.__STD_LIBS = std"; // 将列表存到全局变量 __STD_LIBS 中 luaL_dostring(this->L, save_stdlib_code); /*if(luaL_dostring(this->L, "package.path = \";./luapkg/?/init.lua\"") != LUA_OK)//TODO 修改加载库的默认路径 errno = LUAERR_INIT_FAIL;//加载默认路径*/ if(path !=NULL) { char buf[1024]; snprintf(buf, sizeof(buf), "package.path = package.path .. \";%s\"", path); if(luaL_dostring(this->L,buf) != LUA_OK)//加载用户路径 errno = LUAERR_INIT_FAIL; } this->pkg_cont = 0; this->func_cont = 0; // typed interop 初始状态 this->last_result_type = CJT_NIL; this->last_result_int = 0; this->last_result_num = 0.0; this->last_result_bool = 0; } Lua_runner::~Lua_runner() { lua_close(this->L); } bool Lua_runner::check_file_exists(const char *path) { FILE* file = fopen(path, "r"); if (file) { fclose(file); return true; } return false; } bool Lua_runner::check_luastatue() { /*检查lua状态机状况*/ if(this->L == NULL) { errno = LUAERR_LUA_STATE; return false; } //分为两部分写,防止空指针访问 if(lua_status(this->L) != LUA_OK) { errno = LUAERR_LUA_STATE; return false; } return true; } lua_State *Lua_runner::get_lua_State() { return this->L; } int Lua_runner::load_lib(const char *path,const char *name) { //如果引入哈希表会导致删除包时的多次哈希查询,污染缓存。同时性能仅与数组实现相当 if(!this->check_luastatue()) { return -1; } if(!this->check_file_exists(path)) { errno = LUAERR_LOAD_FILE; return -1; } if(this->pkg_cont>=MAX_LUA_LIB) { errno = LUAERR_LIB_OVERFLOW; return -1; } if(luaL_loadfile(this->L,path)!=LUA_OK) { const char *ret = lua_tostring(this->L, -1); this->reslt = ret;//存储返回值 errno =LUAERR_LOAD_FILE; lua_pop(this->L,1); return -1; } this->pkgs[this->pkg_cont].ref = lua_gettop(this->L)+1; snprintf(pkgs[pkg_cont].name,128,"%s",name); this->pkg_cont++; return 0; } int Lua_runner::unload_lib(const char *name) { int sig = -1; for(int i=0;ipkg_cont;i++) { if(strcmp(this->pkgs[i].name,name) == 0) { sig = i; break;//查找指定的库,查到则将标志位置为库的位置 } } if(sig == -1) { errno = LUAERR_UNLOADLIB_FAIL; return -1;//没有查到返回异常(尝试卸载未加载的库) } /*检查lua状态*/ if(!this->check_luastatue()) { return -1; } lua_remove(this->L,this->pkgs[sig].ref - 1); // ref = gettop+1, 故用 ref-1 定位实际栈位置 for(int j = sig+1;jpkg_cont;j++) { this->pkgs[j-1] = this->pkgs[j];//保持数据结构 this->pkgs[j-1].ref--;//虚拟栈位置同步变化 } this->pkg_cont--; return 1; } int Lua_runner::clean()//进行新一轮调用前一定要先clean清除上个脚本执行的痕迹 { if(!this->check_luastatue()) { return -1; } const char* clean_globals_code = "if _G.__STD_LIBS then " " local std = _G.__STD_LIBS " " for k, v in pairs(_G) do " " if not std[k] then _G[k] = nil end " " end " "end"; luaL_dostring(this->L, clean_globals_code);//清空全局变量 luaL_dostring(this->L, "package.loaded = {}");//清空当前引用的包 // 注: 原先此处有逐个 lua_remove(pkgs[i].ref) 的循环,但 ref=gettop+1 恒越界且多次移除后索引偏移, // 实为死代码;末尾 lua_settop(L,0) 已完整清栈(LuaJIT 下越界 remove 会损坏内存导致崩溃,故删除) this->pkg_cont = 0; // 清理预加载函数 for(int i = 0; i < this->func_cont; i++) { luaL_unref(this->L, LUA_REGISTRYINDEX, this->funcs[i].ref); } this->func_cont = 0; this->reslt ="nil"; lua_settop(this->L, 0);//清空栈 return 0; } //TODO 支持更多类型的参数 int Lua_runner::loadfunction(const char *path,const char *name) { if(!this->check_luastatue()) return -1; if(!this->check_file_exists(path)) { errno = LUAERR_LOAD_FILE; return -1; } if(this->func_cont >= MAX_LUA_FUNC) { errno = LUAERR_FUNC_OVERFLOW; return -1; } // 检查是否已存在同名函数 for(int i = 0; i < this->func_cont; i++) { if(strcmp(this->funcs[i].name, name) == 0) { errno = LUAERR_FUNCTION_NOT_FOUND; return -1; } } // 1. 加载文件到栈顶(编译成 chunk) if(luaL_loadfile(this->L, path) != LUA_OK) { const char *ret = lua_tostring(this->L, -1); this->reslt = ret; errno = LUAERR_LOAD_FILE; lua_pop(this->L, 1); return -1; } // 2. 执行 chunk(顶层代码),期望返回一个函数 if(lua_pcall(this->L, 0, 1, 0) != LUA_OK) { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L, -1); lua_pop(this->L, 1); return -1; } // 3. 检查栈顶是否为函数 if(!lua_isfunction(this->L, -1)) { errno = LUAERR_FUNCTION_INVALID; lua_pop(this->L, 1); return -1; } // 4. 存入 Lua Registry(绝对引用,不受栈变化影响) int ref = luaL_ref(this->L, LUA_REGISTRYINDEX); // 5. 记录到 funcs 表 snprintf(this->funcs[this->func_cont].name, 128, "%s", name); this->funcs[this->func_cont].ref = ref; this->func_cont++; return 0; } int Lua_runner::unloadfunction(const char *name) { int sig = -1; for(int i = 0; i < this->func_cont; i++) { if(strcmp(this->funcs[i].name, name) == 0) { sig = i; break; } } if(sig == -1) { errno = LUAERR_FUNCTION_NOT_FOUND; return -1; } if(!this->check_luastatue()) return -1; // 释放 Registry 引用 luaL_unref(this->L, LUA_REGISTRYINDEX, this->funcs[sig].ref); // 从 funcs 表中移除 for(int j = sig + 1; j < this->func_cont; j++) { this->funcs[j - 1] = this->funcs[j]; } this->func_cont--; return 0; } // ============ typed interop 内部辅助 ============ // 读取 Lua 栈顶值,记录类型到 last_result_*,并把字符串形式同步到 reslt。 // 注意:不弹出栈顶(由调用方决定是否 pop)。 // 计算 lua_pcall 的实际返回值数量并记录结果。 // pre_top: pcall 前的栈顶(含函数与参数);nargs: 传入参数数。 // pcall 后栈顶 = pre_top - nargs - 1(函数) + nres,故 nres = post_top - pre_top + nargs + 1 int Lua_runner::finish_call(int pre_top, int nargs, bool pop_results) { int nres = lua_gettop(this->L) - pre_top + nargs + 1; if(nres <= 0) { // 无返回值:显式置 NIL,不读栈(避免读到上一次调用残留) this->last_result_type = CJT_NIL; this->reslt = "nil"; this->last_result_int = 0; this->last_result_num = 0.0; this->last_result_bool = 0; return nres; } capture_result(); if(pop_results) { // 弹出全部返回值(capture_result 不弹栈) for(int i = 0; i < nres; i++) lua_pop(this->L, 1); } return nres; } void Lua_runner::capture_result() { int top = lua_gettop(this->L); if(top == 0) { // 栈为空:没有返回值 this->last_result_type = CJT_NIL; this->reslt = "nil"; this->last_result_int = 0; this->last_result_num = 0.0; this->last_result_bool = 0; return; } int t = lua_type(this->L, -1); switch (t) { case LUA_TBOOLEAN: this->last_result_type = CJT_BOOL; this->last_result_bool = lua_toboolean(this->L, -1) ? 1 : 0; this->last_result_int = this->last_result_bool; this->last_result_num = this->last_result_bool; this->reslt = this->last_result_bool ? "true" : "false"; break; case LUA_TNUMBER: { // lua_isinteger 区分整型和浮点型 if (lua_isinteger(this->L, -1)) { this->last_result_type = CJT_INT; this->last_result_int = (long long)lua_tointeger(this->L, -1); this->last_result_num = (double)this->last_result_int; this->last_result_bool = this->last_result_int != 0; } else { this->last_result_type = CJT_NUM; this->last_result_num = lua_tonumber(this->L, -1); this->last_result_int = (long long)this->last_result_num; this->last_result_bool = this->last_result_num != 0.0; } this->reslt = lua_tostring(this->L, -1); break; } case LUA_TSTRING: this->last_result_type = CJT_STR; this->reslt = lua_tostring(this->L, -1); this->last_result_int = 0; this->last_result_num = 0.0; this->last_result_bool = false; break; case LUA_TNIL: default: // nil 及 table/function 等复杂类型统一按 CJT_NIL 处理 this->last_result_type = CJT_NIL; this->reslt = "nil"; this->last_result_int = 0; this->last_result_num = 0.0; this->last_result_bool = 0; break; } } int Lua_runner::callfunction(const char *name,const char *arg) { if(!this->check_luastatue()) return -1; // 在 funcs 表中查找(预加载函数表,独立于管道栈 pkgs[]) int sig = -1; for(int i = 0; i < this->func_cont; i++) { if(strcmp(this->funcs[i].name, name) == 0) { sig = i; break; } } if(sig == -1) { errno = LUAERR_FUNCTION_NOT_FOUND; return -1; } // 从 Lua Registry 中取出函数(绝对引用,不受栈变化影响) lua_rawgeti(this->L, LUA_REGISTRYINDEX, this->funcs[sig].ref); // 如果有参数,压入参数 if(arg != NULL) { lua_pushlstring(this->L, arg, strlen(arg)); } int argcount = (arg != NULL) ? 1 : 0; int pre_top = lua_gettop(this->L); if(lua_pcall(this->L, argcount, LUA_MULTRET, 0) == LUA_OK) { finish_call(pre_top, argcount, true);//记录结果并弹出(预加载函数不参与管道) return 0; } else { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L, -1); lua_pop(this->L, 1); return -1; } } // typed 变体共用骨架:查函数→压参数→pcall→finish_call static int callfunc_impl(Lua_runner *r, lua_State *L, const ld_func *funcs, int func_cont, const char *name, std::function push_args, int nargs) { int sig = -1; for(int i = 0; i < func_cont; i++) { if(strcmp(funcs[i].name, name) == 0) { sig = i; break; } } if(sig == -1) { errno = LUAERR_FUNCTION_NOT_FOUND; return -1; } lua_rawgeti(L, LUA_REGISTRYINDEX, funcs[sig].ref); if(nargs > 0) push_args(L); int pre_top = lua_gettop(L); if(lua_pcall(L, nargs, LUA_MULTRET, 0) != LUA_OK) { errno = LUAERR_SCRIPT_ERROR; r->reslt = lua_tostring(L, -1); lua_pop(L, 1); return -1; } r->finish_call(pre_top, nargs, true);//预加载函数不参与管道,弹出结果 return 0; } int Lua_runner::callfunction_int(const char *name, long long val) { if(!this->check_luastatue()) return -1; return callfunc_impl(this, this->L, this->funcs, this->func_cont, name, [val](lua_State *LL) { lua_pushinteger(LL, (lua_Integer)val); }, 1); } int Lua_runner::callfunction_num(const char *name, double val) { if(!this->check_luastatue()) return -1; return callfunc_impl(this, this->L, this->funcs, this->func_cont, name, [val](lua_State *LL) { lua_pushnumber(LL, (lua_Number)val); }, 1); } int Lua_runner::callfunction_bool(const char *name, int val) { if(!this->check_luastatue()) return -1; return callfunc_impl(this, this->L, this->funcs, this->func_cont, name, [val](lua_State *LL) { lua_pushboolean(LL, val ? 1 : 0); }, 1); } int Lua_runner::callfunction_void(const char *name) { if(!this->check_luastatue()) return -1; return callfunc_impl(this, this->L, this->funcs, this->func_cont, name, [](lua_State *) {}, 0); } int Lua_runner::run(const char *path,const char *arg) { if(!this->check_luastatue())//检查lua状态机状态 return -1; if(path != NULL)//加载脚本到栈 { if(this->load_lib(path,path) != 0) return -1; } if(arg != NULL)//压参数入栈 { lua_pushlstring(this->L,arg,strlen(arg)); } if(this->pkg_cont <= 0)//检查是否有可调用chunk { errno = LUAERR_NOCHUNK_FOUND; return -1; } int func_index = this->pkgs[this->pkg_cont-1].ref - 1; int top = lua_gettop(this->L); int argcount = top - func_index;//获取入参数量 if(argcount<0) { errno = LUAERR_LUA_STACK; return -1; }//检查参数数量 int pre_top = top; if(lua_pcall(this->L,argcount,LUA_MULTRET,0)== LUA_OK) { //管道模式:结果留在栈上供下一个节点使用,仅记录类型 finish_call(pre_top, argcount, false); this->pkg_cont--; return 0; } else { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L,-1); this->pkg_cont--; lua_pop(L,1);//错误出栈 return -1; } } int Lua_runner::run_int(const char *path, long long val) { if(!this->check_luastatue()) return -1; if(path != NULL) { if(this->load_lib(path, path) != 0) return -1; } lua_pushinteger(this->L, (lua_Integer)val); if(this->pkg_cont <= 0) { errno = LUAERR_NOCHUNK_FOUND; return -1; } int func_index = this->pkgs[this->pkg_cont-1].ref - 1; int top = lua_gettop(this->L); int argcount = top - func_index; if(argcount < 0) { errno = LUAERR_LUA_STACK; return -1; } int pre_top = top; if(lua_pcall(this->L, argcount, LUA_MULTRET, 0) == LUA_OK) { finish_call(pre_top, argcount, true);//独立调用,弹出结果 this->pkg_cont--; return 0; } else { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L, -1); this->pkg_cont--; lua_pop(this->L, 1); return -1; } } int Lua_runner::run_num(const char *path, double val) { if(!this->check_luastatue()) return -1; if(path != NULL) { if(this->load_lib(path, path) != 0) return -1; } lua_pushnumber(this->L, (lua_Number)val); if(this->pkg_cont <= 0) { errno = LUAERR_NOCHUNK_FOUND; return -1; } int func_index = this->pkgs[this->pkg_cont-1].ref - 1; int top = lua_gettop(this->L); int argcount = top - func_index; if(argcount < 0) { errno = LUAERR_LUA_STACK; return -1; } int pre_top = top; if(lua_pcall(this->L, argcount, LUA_MULTRET, 0) == LUA_OK) { finish_call(pre_top, argcount, true); this->pkg_cont--; return 0; } else { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L, -1); this->pkg_cont--; lua_pop(this->L, 1); return -1; } } int Lua_runner::run_bool(const char *path, int val) { if(!this->check_luastatue()) return -1; if(path != NULL) { if(this->load_lib(path, path) != 0) return -1; } lua_pushboolean(this->L, val ? 1 : 0); if(this->pkg_cont <= 0) { errno = LUAERR_NOCHUNK_FOUND; return -1; } int func_index = this->pkgs[this->pkg_cont-1].ref - 1; int top = lua_gettop(this->L); int argcount = top - func_index; if(argcount < 0) { errno = LUAERR_LUA_STACK; return -1; } int pre_top = top; if(lua_pcall(this->L, argcount, LUA_MULTRET, 0) == LUA_OK) { finish_call(pre_top, argcount, true); this->pkg_cont--; return 0; } else { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L, -1); this->pkg_cont--; lua_pop(this->L, 1); return -1; } } int Lua_runner::run_void(const char *path) { if(!this->check_luastatue()) return -1; if(path != NULL) { if(this->load_lib(path, path) != 0) return -1; } if(this->pkg_cont <= 0) { errno = LUAERR_NOCHUNK_FOUND; return -1; } int func_index = this->pkgs[this->pkg_cont-1].ref - 1; int top = lua_gettop(this->L); int argcount = top - func_index; if(argcount < 0) { errno = LUAERR_LUA_STACK; return -1; } if(lua_pcall(this->L, argcount, LUA_MULTRET, 0) == LUA_OK) { finish_call(top, argcount, true); this->pkg_cont--; return 0; } else { errno = LUAERR_SCRIPT_ERROR; this->reslt = lua_tostring(this->L, -1); this->pkg_cont--; lua_pop(this->L, 1); return -1; } } int Lua_runner::dostring(const char *target) { if(target == NULL) { errno = LUAERR_CALLBACK; return -1; } if(luaL_dostring(this->L,target) != LUA_OK) { errno = LUAERR_CALLBACK; this->reslt = lua_tostring(this->L,-1); lua_pop(L,1);//错误出栈 return -1; } if(lua_gettop(this->L) == 0) { errno = LUAERR_SCRIPT_BAD_RET; this->reslt = ""; return -1; } if(lua_isstring(this->L,-1)){ this->reslt = lua_tostring(this->L,-1); lua_pop(L,1); return 0; } else{ errno = LUAERR_SCRIPT_BAD_RET; lua_pop(L,1); return -1; } } //TODO 实现函数调用 achieve func call via file /* int Lua_runner::callfunction() { return 0; } */