Files
LuaCangjia_api/lib/lua_cj_api.cpp
JianFeeeee 237aab3f36 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直通/大整数保真/错误路径)
2026-08-25 09:29:24 +08:00

576 lines
16 KiB
C++
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "lua_cj_api.h"
extern "C"
{
#include <string.h>
#include "errors.h"
}
using namespace std;
bool check_luastatue(lua_State *L)
{
/*检查lua状态机状况*/
if(L == NULL)
{
errno = LUAERR_LUA_STACK;
return false;
}
//分为两部分写,防止空指针访问
if(lua_status(L) != LUA_OK)
{
errno = LUAERR_LUA_STATE;
return false;
}
return true;
}
int get_errno(void) { return errno; }//获取错误码
// 同步 typed 结果:把 Lua_runner 的 last_result_* 拷贝到外层 lua_runner 结构体
static void sync_typed_result(lua_runner *self, Lua_runner *runner)
{
self->tresult_type = runner->last_result_type;
self->tresult_int = runner->last_result_int;
self->tresult_num = runner->last_result_num;
self->tresult_bool = runner->last_result_bool;
}
/// @brief 加载lua文件到lua虚拟栈
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @param path 需要加载的脚本的位置
/// @param name module命名卸载库时指定
/// @return 0代表正常结束-1表示异常退出
int load_lib(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 = LUAERR_LUA_STATE;
return -1;
}
if(runner->load_lib(path,name)==-1)
return -1;
return 0;
}
/// @brief 卸载lua虚拟栈中的lua文件
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @param name module命名loadlib时的name
/// @return 0代表正常结束-1表示异常退出
int unload_lib(void *selfd,const char *name)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->unload_lib(name)==-1)
return -1;
return 0;
}
/// @brief 运行脚本(可指定入参)
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @param path 脚本路径
/// @param arg 脚本的入参
/// @return 0代表正常结束-1表示异常退出
int run(void *selfd,const char *path,const char *arg)
{
lua_runner* self = (lua_runner*)selfd;
//重定向输入到回调函数
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->run(path,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文件到内存加载文件、执行顶层代码、捕获返回的函数并存入 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 = LUAERR_LUA_STATE;
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 = LUAERR_LUA_STATE;
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 = LUAERR_LUA_STATE;
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());
sync_typed_result(self, runner);
return 0;
}
/*-------------typed interopv0.2.2------------------------*/
int callfunction_int(void *selfd,const char *name,long long val)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->callfunction_int(name,val)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int callfunction_num(void *selfd,const char *name,double val)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->callfunction_num(name,val)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int callfunction_bool(void *selfd,const char *name,int val)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->callfunction_bool(name,val)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int callfunction_void(void *selfd,const char *name)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->callfunction_void(name)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int run_int(void *selfd,const char *path,long long val)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->run_int(path,val)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int run_num(void *selfd,const char *path,double val)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->run_num(path,val)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int run_bool(void *selfd,const char *path,int val)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->run_bool(path,val)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int run_void(void *selfd,const char *path)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->run_void(path)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
sync_typed_result(self, runner);
return 0;
}
int result_type(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_type;}
long long result_int(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_int;}
double result_num(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_num;}
int result_bool(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_bool;}
/*-------------typed interop------------------------*/
/// @brief 执行单句lua语句
/// @param selfd init_lua_runner返回的void指针
/// @param target 执行语句(字符串类型)
/// @return 成功返回0,失败返回-1,并将lua出错原因拷贝至result中
int dostring(void *selfd,const char *target){
lua_runner* self = (lua_runner*)selfd;
//重定向输入到回调函数
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->dostring(target)==-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 self 使用init_lua_runner初始化的lua_runner结构体指针
/// @return 0代表正常结束-1表示异常退出
int cleanup(void *selfd)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = LUAERR_LUA_STATE;
return -1;
}
if(runner->clean()==-1)
return -1;
return 0;
}
/// @brief 释放lua状态机资源
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @return 0代表正常结束-1表示异常退出
int free_lua(void *selfd)
{
lua_runner* self = (lua_runner*)selfd;
delete((Lua_runner*)self->lua_obj);
free(self);
return 0;
}
/*-------------重定向io操作------------------------*/
static const char *full_path(lua_State *L, int isOut)
{
iopath *r = (iopath *)lua_getextraspace(L);
static char buf[512];
snprintf(buf, sizeof(buf), "%s/%s", r->iopath, isOut ? "output" : "input");
return buf;
}
//劫持读取终端输入,触发回调
static int l_tty_read(lua_State *L)
{
iopath *r = (iopath *)lua_getextraspace(L);
if (r->funcs.io_input) r->funcs.io_input();
const char *fname = full_path(L, 0);
FILE *fp = fopen(fname, "rb");
if (!fp) return luaL_error(L, "tty read open fail: %s", fname);
fseek(fp, 0, SEEK_END);
size_t sz = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *tmp = (char*)lua_newuserdata(L, sz);
if(0 ==fread(tmp, 1, sz, fp))
return luaL_error(L, "tty fail to read input: %s", fname);
fclose(fp);
if(remove(fname) != 0)
{
errno = LUAERR_RESET_INPUT_FILE;
return luaL_error(L, "fail to reset input file: %s", fname);
}
lua_pushlstring(L, tmp, sz);
return 1;
}
//劫持到终端输出,输出结束触发回调
static int l_tty_write(lua_State *L)
{
iopath *r = (iopath *)lua_getextraspace(L);
const char *fname = full_path(L, 1);
FILE *fp = fopen(fname, "a");
if (!fp) return luaL_error(L, "tty write open fail: %s", fname);
int n = lua_gettop(L);
for (int i = 1; i <= n; ++i)
if (lua_isstring(L, i)) fputs(lua_tostring(L, i), fp);
fclose(fp);
if (r->funcs.io_output) r->funcs.io_output();
return 0;
}
static int l_print(lua_State *L) {
iopath *r = (iopath *)lua_getextraspace(L);
const char *fname = full_path(L, 1); // 输出到 output 文件
FILE *fp = fopen(fname, "a");
if (!fp) return luaL_error(L, "print redirect open fail: %s", fname);
int n = lua_gettop(L);
for (int i = 1; i <= n; ++i) {
if (i > 1) fputc('\t', fp);
const char *str = luaL_tolstring(L, i, NULL);
fputs(str, fp);
lua_pop(L, 1);
}
fputc('\n', fp);
fclose(fp);
if (r->funcs.io_output) r->funcs.io_output();
return 0;
}
/*空实现*/
static int l_tty_flush(lua_State *L)
{
(void)L;
return 0;
}
static int l_tty_close(lua_State *L)
{
(void)L;
return 0;
}
/*空实现(不需要)*/
static int l_tty_call(lua_State *L)
{
// 当尝试调用tty对象时返回自身或执行某些操作
lua_pushvalue(L, 1); // 返回对象自身
return 1;
}
static void push_tty_file(lua_State *L, int isout, const luaL_Reg *fake_tty_meta)
{
lua_newuserdata(L, sizeof(int));
luaL_newmetatable(L, isout ? "tty_out" : "tty_in");
luaL_setfuncs(L, fake_tty_meta, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
// 添加__call元方法
lua_pushcfunction(L, l_tty_call);
lua_setfield(L, -2, "__call");
// 添加__tostring
lua_pushstring(L, isout ? "TTY_OUT" : "TTY_IN");
lua_setfield(L, -2, "__tostring");
lua_setmetatable(L, -2);
}
int redirecct_path(lua_State *L)
{
if(!check_luastatue(L)){
errno = LUAERR_LUA_STATE;
return -1;
}
iopath *p = (iopath*)lua_getextraspace(L);
static const luaL_Reg fake_methods[] = {
{"read", l_tty_read},
{"write", l_tty_write},
{"flush", l_tty_flush},
{"close", l_tty_close},
{NULL, NULL}
};
/* 1. 把 io.output() 换成 tty 替身 */
push_tty_file(L, 1,fake_methods);
lua_getglobal(L, "io");
lua_pushvalue(L, -2);
lua_setfield(L, -2, "output"); /* io.output = 替身 */
lua_pop(L, 2);
/* 2. 把 io.input() 换成 tty 替身 */
push_tty_file(L, 0,fake_methods);
lua_getglobal(L, "io");
lua_pushvalue(L, -2);
lua_setfield(L, -2, "input"); /* io.input = 替身 */
lua_pop(L, 2);
lua_pushcfunction(L, l_print);
lua_setglobal(L, "print");
lua_getglobal(L, "io");
lua_pushcfunction(L, l_tty_read);
lua_setfield(L, -2, "read");
lua_pushcfunction(L, l_tty_write);
lua_setfield(L, -2, "write");
lua_pop(L, 1);
return 0;
}
/*----------------重定向io操作------------------------*/
//获取对象中的返回值
char *getresult(void *selfd){lua_runner*self =(lua_runner*) selfd;return self->result;}
/// @brief 初始化lua解释器
/// @param pathio 重定向io目录
/// @param pkgpath 用户包搜索目录
/// @param input 输入回调函数
/// @param output 输出回调函数
/// @return 0正常结束-1异常退出
void *init_lua_runner(const char *pathio,const char *pkgpath,int(*input)(),int(*output)())//该函数挂载到cj构造函数中执行
{
//分配内存
lua_runner *self = (lua_runner*)malloc(sizeof(lua_runner));
// typed interop 字段初始化
self->tresult_type = CJT_NIL;
self->tresult_int = 0;
self->tresult_num = 0.0;
self->tresult_bool = 0;
//创建对象
self->lua_obj = (void*)new Lua_runner(pkgpath);
if(errno != 0)
return NULL;
if(self->lua_obj == NULL)
{
errno = LUAERR_CLASS_LOST;
return NULL;
}
//提取对象
Lua_runner *runner = (Lua_runner*)self->lua_obj;
//提取lua状态机
lua_State *L = runner->get_lua_State();
if(!check_luastatue(L)){
errno = LUAERR_LUA_STATE;
return NULL;
}
iopath *io_path = (iopath*)lua_getextraspace(L);
//申请额外空间
if(pathio == NULL)
{
goto WITHOUT_REDIRECT;
}
if(io_path == NULL){
errno = LUAERR_CALLBACK;
return NULL;
}
//装载重定向函数
io_path->funcs.io_input = input;
io_path->funcs.io_output = output;
//装载重定向路径
strcpy(io_path->iopath,pathio);
//注册重定向
if(redirecct_path(L)==-1){
errno = LUAERR_LUA_STATE;
return NULL;
}
WITHOUT_REDIRECT:
return (void*)self;
}