feat: typed interop 原始类型直通映射 (Int64/Float64/Bool)

- C++ 层: callfunction_int/num/bool/void + run_int/num/bool/void
- 新增 capture_result()/finish_call() 正确计算 lua_pcall 实际返回值数量,
  修复无返回值场景下误读栈残留的问题
- C FFI 层: 11 个新导出函数 + lua_runner 结构体 tresult_* 镜像字段
- 仓颉层: callFunctionInt/Num/Bool, runScriptInt/Num/Bool, resultType()
  带严格类型校验(不匹配抛 LUAERR_RESULT_TYPE)
- 大整数跨 2^53 保真(字符串路径做不到)
- 管道模式语义保留给字符串 API; typed run_* 为独立调用保持栈清洁
- GTest 新增 10 个 typed 测试用例(共 44 个全部通过)
- 独立程序验证仓颉层运行时正确性(int/num/bool直通/大整数保真/错误路径)
This commit is contained in:
JianFeeeee
2026-08-25 09:29:24 +08:00
parent 42e8b7676d
commit 237aab3f36
13 changed files with 1091 additions and 112 deletions

View File

@ -1,5 +1,6 @@
#include "lua_runner.hpp"
#include <cstring>
#include <functional>
extern "C"
{
@ -13,7 +14,7 @@ Lua_runner::Lua_runner(const char *path)
this->L = luaL_newstate();
errno = 0;//清除老错误信息
if(this->L == NULL){
errno = NAPI_LUA_STATE_ERROR;
errno = LUAERR_LUA_STATE;
return ;
}
luaL_openlibs(this->L);//创建lua状态机打开标准库
@ -24,8 +25,8 @@ 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;//加载默认路径*/
"package.path = \";./luapkg/?/init.lua\"") != LUA_OK)//TODO 修改加载库的默认路径
errno = LUAERR_INIT_FAIL;//加载默认路径*/
if(path !=NULL)
{
char buf[1024];
@ -33,10 +34,15 @@ Lua_runner::Lua_runner(const char *path)
"package.path = package.path .. \";%s\"",
path);
if(luaL_dostring(this->L,buf) != LUA_OK)//加载用户路径
errno = NAPI_LUA_INITFAIL;
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()
@ -59,13 +65,13 @@ bool Lua_runner::check_luastatue()
/*检查lua状态机状况*/
if(this->L == NULL)
{
errno = NAPI_LUA_STATE_ERROR;
errno = LUAERR_LUA_STATE;
return false;
}
//分为两部分写,防止空指针访问
if(lua_status(this->L) != LUA_OK)
{
errno = NAPI_LUA_STATE_ERROR;
errno = LUAERR_LUA_STATE;
return false;
}
return true;
@ -86,19 +92,19 @@ int Lua_runner::load_lib(const char *path,const char *name)
}
if(!this->check_file_exists(path))
{
errno = NAPI_LOAD_FILE_ERROR;
errno = LUAERR_LOAD_FILE;
return -1;
}
if(this->pkg_cont>=MAX_LUA_LIB)
{
errno = NAPI_LUALIB_LOAD_OVER_STACK;
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 =NAPI_LOAD_FILE_ERROR;
errno =LUAERR_LOAD_FILE;
lua_pop(this->L,1);
return -1;
}
@ -122,7 +128,7 @@ int Lua_runner::unload_lib(const char *name)
}
if(sig == -1)
{
errno = NAPI_UNLOADLIB_FAIL;
errno = LUAERR_UNLOADLIB_FAIL;
return -1;//没有查到返回异常(尝试卸载未加载的库)
}
/*检查lua状态*/
@ -179,12 +185,12 @@ int Lua_runner::loadfunction(const char *path,const char *name)
return -1;
if(!this->check_file_exists(path))
{
errno = NAPI_LOAD_FILE_ERROR;
errno = LUAERR_LOAD_FILE;
return -1;
}
if(this->func_cont >= MAX_LUA_FUNC)
{
errno = NAPI_LOAD_FUNCTION_OVER;
errno = LUAERR_FUNC_OVERFLOW;
return -1;
}
// 检查是否已存在同名函数
@ -192,7 +198,7 @@ int Lua_runner::loadfunction(const char *path,const char *name)
{
if(strcmp(this->funcs[i].name, name) == 0)
{
errno = NAPI_FUNCTION_NOT_FOUND;
errno = LUAERR_FUNCTION_NOT_FOUND;
return -1;
}
}
@ -202,7 +208,7 @@ int Lua_runner::loadfunction(const char *path,const char *name)
{
const char *ret = lua_tostring(this->L, -1);
this->reslt = ret;
errno = NAPI_LOAD_FILE_ERROR;
errno = LUAERR_LOAD_FILE;
lua_pop(this->L, 1);
return -1;
}
@ -210,7 +216,7 @@ int Lua_runner::loadfunction(const char *path,const char *name)
// 2. 执行 chunk顶层代码期望返回一个函数
if(lua_pcall(this->L, 0, 1, 0) != LUA_OK)
{
errno = NAPI_SCRIPT_ERROR;
errno = LUAERR_SCRIPT_ERROR;
this->reslt = lua_tostring(this->L, -1);
lua_pop(this->L, 1);
return -1;
@ -219,7 +225,7 @@ int Lua_runner::loadfunction(const char *path,const char *name)
// 3. 检查栈顶是否为函数
if(!lua_isfunction(this->L, -1))
{
errno = NAPI_FUNCTION_NOT_VALID;
errno = LUAERR_FUNCTION_INVALID;
lua_pop(this->L, 1);
return -1;
}
@ -248,7 +254,7 @@ int Lua_runner::unloadfunction(const char *name)
}
if(sig == -1)
{
errno = NAPI_FUNCTION_NOT_FOUND;
errno = LUAERR_FUNCTION_NOT_FOUND;
return -1;
}
@ -268,6 +274,98 @@ int Lua_runner::unloadfunction(const char *name)
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())
@ -285,7 +383,7 @@ int Lua_runner::callfunction(const char *name,const char *arg)
}
if(sig == -1)
{
errno = NAPI_FUNCTION_NOT_FOUND;
errno = LUAERR_FUNCTION_NOT_FOUND;
return -1;
}
@ -299,23 +397,88 @@ int Lua_runner::callfunction(const char *name,const char *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)
{
if(lua_isstring(this->L, -1))
this->reslt = lua_tostring(this->L, -1);
lua_pop(this->L, 1);
finish_call(pre_top, argcount, true);//记录结果并弹出(预加载函数不参与管道)
return 0;
}
else
{
errno = NAPI_SCRIPT_ERROR;
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<void(lua_State *)> 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状态机状态
@ -332,7 +495,7 @@ int Lua_runner::run(const char *path,const char *arg)
}
if(this->pkg_cont <= 0)//检查是否有可调用chunk
{
errno = NAPI_NOCHUNK_FOUND;
errno = LUAERR_NOCHUNK_FOUND;
return -1;
}
int func_index = this->pkgs[this->pkg_cont-1].ref - 1;
@ -340,19 +503,20 @@ int Lua_runner::run(const char *path,const char *arg)
int argcount = top - func_index;//获取入参数量
if(argcount<0)
{
errno = NAPI_LUA_STACK_ERROR;
errno = LUAERR_LUA_STACK;
return -1;
}//检查参数数量
int pre_top = top;
if(lua_pcall(this->L,argcount,LUA_MULTRET,0)== LUA_OK)
{
if(lua_isstring(this->L,-1))
this->reslt = lua_tostring(this->L,-1);
//管道模式:结果留在栈上供下一个节点使用,仅记录类型
finish_call(pre_top, argcount, false);
this->pkg_cont--;
return 0;
}
else
{
errno = NAPI_SCRIPT_ERROR;
errno = LUAERR_SCRIPT_ERROR;
this->reslt = lua_tostring(this->L,-1);
this->pkg_cont--;
lua_pop(L,1);//错误出栈
@ -360,22 +524,180 @@ int Lua_runner::run(const char *path,const char *arg)
}
}
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 = NAPI_ERROR_FUNCS;
errno = LUAERR_CALLBACK;
return -1;
}
if(luaL_dostring(this->L,target) != LUA_OK)
{
errno = NAPI_ERROR_FUNCS;
errno = LUAERR_CALLBACK;
this->reslt = lua_tostring(this->L,-1);
lua_pop(L,1);//错误出栈
return -1;
}
if(lua_gettop(this->L) == 0) {
errno = NAPI_SCRIPT_BAD_RET;
errno = LUAERR_SCRIPT_BAD_RET;
this->reslt = "";
return -1;
}
@ -385,7 +707,7 @@ int Lua_runner::dostring(const char *target)
return 0;
}
else{
errno = NAPI_SCRIPT_BAD_RET;
errno = LUAERR_SCRIPT_BAD_RET;
lua_pop(L,1);
return -1;
}