diff --git a/cjpm.toml b/cjpm.toml index 51f978b..d5e9a12 100644 --- a/cjpm.toml +++ b/cjpm.toml @@ -8,7 +8,7 @@ output-type ="executable" [dependencies] [ffi.c] -luacjapi.path = "./lib/build/luacjapi" +luacjapi.path = "./lib/build" [scripts] pre-build = "cjpm run build.cj pre-build" diff --git a/lib/lua_cj_api.cpp b/lib/lua_cj_api.cpp index e4de239..c238317 100755 --- a/lib/lua_cj_api.cpp +++ b/lib/lua_cj_api.cpp @@ -308,7 +308,7 @@ void *init_lua_runner(const char *pathio,const char *pkgpath,int(*input)(),int(* if(pathio == NULL) { errno = NAPI_LUA_MISS_REDIRECT; - return NULL; + goto WITHOUT_REDIRECT; } //装载重定向函数 io_path->funcs.io_input = input; @@ -320,7 +320,7 @@ void *init_lua_runner(const char *pathio,const char *pkgpath,int(*input)(),int(* errno = NAPI_LUA_STATE_ERROR; return NULL; } - +WITHOUT_REDIRECT: return (void*)self; } diff --git a/src/bridge.cj b/src/bridge.cj new file mode 100644 index 0000000..c4447ca --- /dev/null +++ b/src/bridge.cj @@ -0,0 +1,128 @@ +package LuaCangjie_api + +import std.collection.* + +// ==================== FFI底层 ==================== + +type IOCallback = CFunc<() -> Int32> + +@C +foreign func init_lua_runner(pathio: CString, pkgpath: CString, input: IOCallback, output: IOCallback): CPointer +@C +foreign func load_lib(selfd: CPointer, path: CString, name: CString): Int32 +@C +foreign func unload_lib(selfd: CPointer, name: CString): Int32 +@C +foreign func run(selfd: CPointer, path: CString, arg: CString): Int32 +@C +foreign func cleanup(selfd: CPointer): Int32 +@C +foreign func get_errno(): Int32 +@C +foreign func getresult(selfd: CPointer): CString +@C +foreign func free_lua(selfd: CPointer): Int32 + +// ==================== 工具函数 ==================== + +@C +func defaultIO(): Int32 { + // 默认输入回调,返回0表示成功 + 0 +} + + +private func toCStr(s: String): CString{ + if (s.isEmpty()) { + var tmp = CString(CPointer()); + return tmp + } + + else { + unsafe { LibC.mallocCString(s) } + } +} + +// CString转String:通过 CPointer 构造 CString 后调用 toString() +private func toString(ptr: CString): String { + if (ptr.isNull()) { return "" } + // 将 CPointer 强制转换为 CPointer + // 通过 CPointer 构造 CString + return ptr.toString() +} + +// ==================== 异常 ==================== + +public class LuaError <: Exception { + public let code: Int32 + public init(code: Int32, msg: String) { super(msg); this.code = code } +} + + + +// ==================== 主类 ==================== + +public class LuaRunner { + private var handle: CPointer + private var cachedResult: String = "" + private var ioInput: IOCallback + private var ioOutput: IOCallback + //pkgpath 重定向lua状态机包搜索路径 + //pathio 重定向io输出到pathio路径下 + //@param output 类型function 用于lua内部触发输出时调用的回调函数 + //@param input 类型function 用于lua内部触发输入时的调用的回调函数 + //@brief 构造lua状态机 + public init( input!: IOCallback = defaultIO, output!: IOCallback = defaultIO,pathio!: String='' , pkgpath!: String='') { + this.ioInput = input + this.ioOutput = output + var tmpio = toCStr(pathio); + var tmppkg = toCStr(pkgpath); + + this.handle = unsafe { init_lua_runner(tmpio,tmppkg, input, output) } + unsafe{ + LibC.free(tmpio); + LibC.free(tmppkg); + } + if (this.handle.isNull()) { throw LuaError(-1, "Init failed") } + } + + ~init() { + if (!this.handle.isNull()) { + unsafe { free_lua(this.handle) } + this.handle = CPointer() + } + } + + public func load(path: String, name: String): This { + let result = unsafe { load_lib(this.handle, toCStr(path), toCStr(name)) } + if (result != 0) { + throw LuaError(unsafe { get_errno() }, toString(unsafe { getresult(this.handle) })) + } + return this + } + + public func unload(name: String): This { + let result = unsafe { unload_lib(this.handle, toCStr(name)) } + if (result != 0) { + throw LuaError(unsafe { get_errno() }, toString(unsafe { getresult(this.handle) })) + } + return this + } + + public func runScript(path: String, arg: String): String { + let code = unsafe { run(this.handle, toCStr(path), toCStr(arg)) } + this.cachedResult = toString(unsafe { getresult(this.handle) }) + if (code != 0) { throw LuaError(unsafe { get_errno() }, this.cachedResult) } + return this.cachedResult + } + + public func result(): String { this.cachedResult } + + public func error(): String { toString(unsafe { getresult(this.handle) }) } + + public func clear(): This { + let result = unsafe { cleanup(this.handle) } + if (result != 0) { throw LuaError(unsafe { get_errno() }, "Cleanup failed") } + return this + } +} \ No newline at end of file diff --git a/src/main.cj b/src/main.cj index ca1756e..877e455 100644 --- a/src/main.cj +++ b/src/main.cj @@ -1,17 +1,31 @@ package LuaCangjie_api -@C -struct lua_runner { +import std.console.* -} +// ==================== @C 修饰的回调函数 ==================== + + +// ==================== main ==================== -foreign{ - func init_lua_runner(self:CPointer,pathio:CString,pkgpath:CString,io_input:CFunc<() -> Int32>,io_output:CFunc<() -> Int32>):Int32 - func get_errno():Int32 - func getresult(runner:CPointer):CString - func run(self:CPointer,path:CString,arg:CString):Int32 -} main(): Int64 { - println("hello world") - return 0 + try { + // 创建 LuaRunner 实例,使用 @C 函数作为回调 + let runner = LuaRunner() + + println("LuaRunner initialized successfully") + + // 运行 test.lua 脚本,无参数传入 + let result = runner.runScript("test.lua", "") + + println("Script output: ${result}") + + // 清理缓存(析构函数会自动释放资源) + runner.clear() + + } catch (e: LuaError) { + println("Error [code=${e.code}]: ${e.message}") + return 1 + } + + 0 } \ No newline at end of file diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..e75154b --- /dev/null +++ b/test.lua @@ -0,0 +1 @@ +print("hello world") \ No newline at end of file