完成桥接层

This commit is contained in:
2026-03-19 22:04:07 +08:00
parent 4ee065954e
commit a5eb303c4b
5 changed files with 157 additions and 14 deletions

128
src/bridge.cj Normal file
View File

@ -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<Unit>
@C
foreign func load_lib(selfd: CPointer<Unit>, path: CString, name: CString): Int32
@C
foreign func unload_lib(selfd: CPointer<Unit>, name: CString): Int32
@C
foreign func run(selfd: CPointer<Unit>, path: CString, arg: CString): Int32
@C
foreign func cleanup(selfd: CPointer<Unit>): Int32
@C
foreign func get_errno(): Int32
@C
foreign func getresult(selfd: CPointer<Unit>): CString
@C
foreign func free_lua(selfd: CPointer<Unit>): Int32
// ==================== 工具函数 ====================
@C
func defaultIO(): Int32 {
// 默认输入回调返回0表示成功
0
}
private func toCStr(s: String): CString{
if (s.isEmpty()) {
var tmp = CString(CPointer<UInt8>());
return tmp
}
else {
unsafe { LibC.mallocCString(s) }
}
}
// CString转String通过 CPointer<UInt8> 构造 CString 后调用 toString()
private func toString(ptr: CString): String {
if (ptr.isNull()) { return "" }
// 将 CPointer<Int8> 强制转换为 CPointer<UInt8>
// 通过 CPointer<UInt8> 构造 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<Unit>
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<Unit>()
}
}
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
}
}