mirror of
https://gitcode.com/JianFeeeee/LuaCangjia_api.git
synced 2026-09-20 00:48:47 +00:00
feat: 实现loadFunction预加载函数能力 + AI辅助编程标识
- 新增 loadFunction/callFunction/unloadFunction 预加载函数 API - 预加载语义:加载文件→顶层执行一次→返回函数存入Lua Registry→可多次调用 - 与管道模式(load/runScript)存储完全解耦:funcs[]+Registry vs pkgs[]+虚拟栈 - 新增错误码 5023/5024/5025 - 新增单元测试:仓颉侧 8 个 + C++ GTest 侧 11 个 - 本机以 Cangjie 1.1.0 实编译并通过功能运行验证 - README/doc 增加 AI 辅助编程标识及预加载函数模式说明
This commit is contained in:
@ -23,5 +23,8 @@
|
||||
#define NAPI_ERROR_FUNCS 5020 //函数调用错误
|
||||
#define NAPI_CHDIR_ERROR 5021 //切换工作目录失败,可能导致包搜索错误,日志写入路径错误等
|
||||
#define NAPI_NOCHUNK_FOUND 5022 //没有找到待调用的函数
|
||||
#define NAPI_FUNCTION_NOT_FOUND 5023 //通过callfunction调用时未找到指定函数
|
||||
#define NAPI_LOAD_FUNCTION_OVER 5024 //预加载函数数量超过上限
|
||||
#define NAPI_FUNCTION_NOT_VALID 5025 //预加载文件顶层执行后返回的不是函数
|
||||
|
||||
#endif
|
||||
@ -86,6 +86,65 @@ int run(void *selfd,const char *path,const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief 预加载lua文件到内存:加载文件、执行顶层代码、捕获返回的函数并存入 Registry,供后续 callfunction 多次调用
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param path 需要加载的文件路径
|
||||
/// @param name 函数名称(callfunction/unloadfunction时使用)
|
||||
/// @return 0代表正常结束,-1表示异常退出
|
||||
int loadfunction(void *selfd,const char *path,const char *name)
|
||||
{
|
||||
lua_runner* self = (lua_runner*)selfd;
|
||||
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
|
||||
if(runner == NULL)
|
||||
{
|
||||
errno = NAPI_LUA_STATE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if(runner->loadfunction(path,name)==-1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief 卸载预加载的函数(释放 Registry 引用)
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param name loadfunction加载时的函数名称
|
||||
/// @return 0代表正常结束,-1表示异常退出
|
||||
int unloadfunction(void *selfd,const char *name)
|
||||
{
|
||||
lua_runner* self = (lua_runner*)selfd;
|
||||
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
|
||||
if(runner == NULL)
|
||||
{
|
||||
errno = NAPI_LUA_STATE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if(runner->unloadfunction(name)==-1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief 按名称调用已预加载的函数(从 Registry 取出,不消耗该函数,可重复调用)
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param name loadfunction加载时的函数名称
|
||||
/// @param arg 传递给函数的单参数(可为NULL)
|
||||
/// @return 成功返回0,失败返回-1,并将lua出错原因拷贝至result中
|
||||
int callfunction(void *selfd,const char *name,const char *arg)
|
||||
{
|
||||
lua_runner* self = (lua_runner*)selfd;
|
||||
Lua_runner *runner = (Lua_runner*)self->lua_obj;
|
||||
if(runner == NULL)
|
||||
{
|
||||
errno = NAPI_LUA_STATE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if(runner->callfunction(name,arg)==-1){
|
||||
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
|
||||
return -1;
|
||||
}
|
||||
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief 执行单句lua语句
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param target 执行语句(字符串类型)
|
||||
|
||||
@ -55,6 +55,26 @@ int load_lib(void *selfd,const char *path,const char *name);
|
||||
/// @return 成功返回0,失败返回-1
|
||||
int unload_lib(void *selfd,const char *name);
|
||||
|
||||
/// @brief 预加载lua文件到内存:加载文件、执行顶层代码、捕获返回的函数并存入 Registry,供后续 callfunction 多次调用
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param path 需要加载的文件路径
|
||||
/// @param name 函数名称(callfunction/unloadfunction时使用)
|
||||
/// @return 0代表正常结束,-1表示异常退出
|
||||
int loadfunction(void *selfd,const char *path,const char *name);
|
||||
|
||||
/// @brief 卸载预加载的函数(释放 Registry 引用)
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param name loadfunction加载时的函数名称
|
||||
/// @return 0代表正常结束,-1表示异常退出
|
||||
int unloadfunction(void *selfd,const char *name);
|
||||
|
||||
/// @brief 按名称调用已预加载的函数(从 Registry 取出,不消耗该函数,可重复调用)
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param name loadfunction加载时的函数名称
|
||||
/// @param arg 传递给函数的单参数(可为NULL)
|
||||
/// @return 成功返回0,失败返回-1,并将lua出错原因拷贝至result中
|
||||
int callfunction(void *selfd,const char *name,const char *arg);
|
||||
|
||||
/// @brief 运行lua脚本
|
||||
/// @param selfd init_lua_runner返回的void指针
|
||||
/// @param path 脚本路径
|
||||
|
||||
@ -25,7 +25,7 @@ Lua_runner::Lua_runner(const char *path)
|
||||
luaL_dostring(this->L, save_stdlib_code);
|
||||
/*if(luaL_dostring(this->L,
|
||||
"package.path = \";/data/storage/el2/luapkg/?/init.lua\"") != LUA_OK)//TODO 修改加载库的默认路径指向沙盒内路径
|
||||
errno = NAPI_LUA_INITFAIL;//加载默认路径*/
|
||||
errno = NAPI_LUA_INITFAIL;//加载默认路径*/
|
||||
if(path !=NULL)
|
||||
{
|
||||
char buf[1024];
|
||||
@ -36,6 +36,7 @@ Lua_runner::Lua_runner(const char *path)
|
||||
errno = NAPI_LUA_INITFAIL;
|
||||
}
|
||||
this->pkg_cont = 0;
|
||||
this->func_cont = 0;
|
||||
}
|
||||
|
||||
Lua_runner::~Lua_runner()
|
||||
@ -160,12 +161,161 @@ int Lua_runner::clean()//进行新一轮调用前一定要先clean清除上个
|
||||
lua_remove(this->L,this->pkgs[i].ref);
|
||||
}
|
||||
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 = NAPI_LOAD_FILE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if(this->func_cont >= MAX_LUA_FUNC)
|
||||
{
|
||||
errno = NAPI_LOAD_FUNCTION_OVER;
|
||||
return -1;
|
||||
}
|
||||
// 检查是否已存在同名函数
|
||||
for(int i = 0; i < this->func_cont; i++)
|
||||
{
|
||||
if(strcmp(this->funcs[i].name, name) == 0)
|
||||
{
|
||||
errno = NAPI_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 = NAPI_LOAD_FILE_ERROR;
|
||||
lua_pop(this->L, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2. 执行 chunk(顶层代码),期望返回一个函数
|
||||
if(lua_pcall(this->L, 0, 1, 0) != LUA_OK)
|
||||
{
|
||||
errno = NAPI_SCRIPT_ERROR;
|
||||
this->reslt = lua_tostring(this->L, -1);
|
||||
lua_pop(this->L, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 3. 检查栈顶是否为函数
|
||||
if(!lua_isfunction(this->L, -1))
|
||||
{
|
||||
errno = NAPI_FUNCTION_NOT_VALID;
|
||||
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 = NAPI_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;
|
||||
}
|
||||
|
||||
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 = NAPI_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;
|
||||
|
||||
if(lua_pcall(this->L, argcount, LUA_MULTRET, 0) == LUA_OK)
|
||||
{
|
||||
if(lua_isstring(this->L, -1))
|
||||
this->reslt = lua_tostring(this->L, -1);
|
||||
lua_pop(this->L, 1);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = NAPI_SCRIPT_ERROR;
|
||||
this->reslt = lua_tostring(this->L, -1);
|
||||
lua_pop(this->L, 1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int Lua_runner::run(const char *path,const char *arg)
|
||||
{
|
||||
if(!this->check_luastatue())//检查lua状态机状态
|
||||
|
||||
@ -15,17 +15,28 @@ typedef struct loaded_package
|
||||
|
||||
}ld_pkg;
|
||||
|
||||
// 预加载函数表:使用 luaL_ref 存入 Lua Registry,ref 为绝对索引,不受栈变化影响
|
||||
#define MAX_LUA_FUNC 20
|
||||
typedef struct loaded_function
|
||||
{
|
||||
char name[128];
|
||||
int ref; // luaL_ref 返回的绝对索引
|
||||
|
||||
}ld_func;
|
||||
|
||||
#ifdef __cplusplus
|
||||
class Lua_runner//lua运行器对象
|
||||
{
|
||||
public:
|
||||
Lua_runner(const char *path = NULL);//创建lua状态机并持久化持有
|
||||
~Lua_runner();//销毁状态机
|
||||
int load_lib(const char *path,const char *name);//加载库
|
||||
int load_lib(const char *path,const char *name);//加载库(块压栈)
|
||||
int unload_lib(const char *name);//解除加载
|
||||
int loadfunction(const char *path,const char *name);//预加载函数(顶层执行,结果存入独立函数表)
|
||||
int unloadfunction(const char *name);//卸载预加载函数
|
||||
int callfunction(const char *name,const char *arg);//按名称调用已预加载的函数
|
||||
int run(const char *path = NULL,const char *arg = NULL);
|
||||
int clean();//清除状态机缓存
|
||||
//int callfunction();
|
||||
int dostring(const char *target);
|
||||
std::string reslt;
|
||||
lua_State *get_lua_State();
|
||||
@ -33,6 +44,8 @@ class Lua_runner//lua运行器对象
|
||||
lua_State *L;
|
||||
int pkg_cont;
|
||||
ld_pkg pkgs[MAX_LUA_LIB];
|
||||
int func_cont;
|
||||
ld_func funcs[MAX_LUA_FUNC];
|
||||
bool check_luastatue();
|
||||
bool check_file_exists(const char *path);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user