Files
LuaCangjia_api/doc/api.md
2026-04-05 09:14:56 +08:00

151 lines
7.4 KiB
Markdown
Raw 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.

# API 文档
### 类:`LuaRunner`
Lua 虚拟机的主要管理类。
### 构造函数
`public init(input: IOCallback = defaultIO, output: IOCallback = defaultIO, pathio: String = "", pkgpath: String = "")`
- **参数**:
- `input`: `IOCallback` 类型。Lua 调用 `io.read` 时触发的回调函数。
- `output`: `IOCallback` 类型。Lua 调用 `print``io.write` 时触发的回调函数。
- `pathio`: `String` 类型。指定 I/O 重定向的文件交换目录路径。为空则不重定向。
- `pkgpath`: `String` 类型。设置 Lua 的 `package.path`,用于自定义模块搜索路径(如 `"./lib/?.lua"`)。
### 方法
| 方法 | 描述 | 返回值 |
| :--- | :--- | :--- |
| `load(path: String, name: String): This` | 加载指定路径的 Lua 文件,编译后以 `name` 为标识压入内部栈。 | 实例本身 (`This`) |
| `unload(name: String): This` | 从内部栈中卸载由 `name` 标识的模块。 | 实例本身 (`This`) |
| `runScript(path: String, arg: String): String` | **核心执行方法**。 - 若 `path` 非空:加载并执行该脚本,`arg` 作为单参数传入。 - 若 `path` 为空:触发**管道模式**,调用栈顶函数,并按内部栈布局自动计算参数数量。 | 脚本执行的字符串结果 |
| `doString(target: String): String` | 执行单条 Lua 代码字符串。`target` 为合法的 Lua 代码片段,必须返回字符串类型结果。 | 执行结果的字符串 |
| `clear(): This` | 清理 Lua 状态机,清空全局变量和所有加载的库,恢复到初始状态。 | 实例本身 (`This`) |
| `result(): String` | 获取最近一次 `runScript``doString` 成功执行的返回值。 | 字符串 |
| `error(): String` | 获取最近一次错误的原始描述信息。 | 字符串 |
## 异常类:`LuaError`
所有 Lua 相关操作失败时抛出的异常。
- **属性**:
- `code: Int32`:错误码,用于程序逻辑判断。
- **方法**:
- `getMessage(): String`:获取错误的详细描述。
### 错误码对照表
| 错误码 | 宏定义 | 描述 |
| :----- | :--------------------- | :------------------------------------------------------- |
| 5001 | `NAPI_JSON_LOAD_FAIL` | JSON 文件加载失败。 |
| 5002 | `NAPI_MALLOC_FAIL` | 内存分配失败。 |
| 5003 | `NAPI_LOAD_FILE_ERROR` | 文件加载错误,包含路径、权限以及脚本编译期语法错误。 |
| 5004 | `NAPI_SCRIPT_RUNNER_INVALID` | 脚本运行器初始化失败或实例无效。 |
| 5005 | `NAPI_LUA_STATE_ERROR` | Lua 状态机初始化失败或已损坏。 |
| 5006 | `NAPI_JSON_RESOLVE_FAIL` | JSON 解析错误,可能是格式问题。 |
| 5007 | `NAPI_JSON_FORMATE_ERROR` | JSON 格式错误,不符合 MCP 常见格式。 |
| 5008 | `NAPI_MISSING_JSON_ARG` | 无法从 JSON 中解析到所需参数。 |
| 5009 | `NAPI_LUA_STACK_NOSPACE` | Lua 栈空间不足。 |
| 5010 | `NAPI_SCRIPT_ERROR` | 脚本内部错误,请通过 `result()` 获取详细信息。 |
| 5011 | `NAPI_SCRIPT_BAD_RET` | 脚本返回值错误,当前版本仅支持字符串返回。 |
| 5012 | `NAPI_UNLOADLIB_FAIL` | 尝试卸载未加载的库。 |
| 5013 | `NAPI_LUAFUN_NOFOUND` | 调用不符合单输入单输出约定。 |
| 5014 | `NAPI_LUA_STACK_ERROR` | 函数调用时栈大小小于最小约定大小。 |
| 5015 | `NAPI_LUA_INITFAIL` | Lua 状态机初始化错误。 |
| 5016 | `NAPI_LUALIB_LOAD_OVER_STACK` | 加载的库数量超过上限(最大 20 个)。 |
| 5017 | `NAPI_LUA_CLASS_LOST` | 底层 LuaRunner 对象丢失。 |
| 5018 | `NAPI_LUA_MISS_REDIRECT` | 缺少用于重定向的文件路径。 |
| 5019 | `NAPI_RESET_INPUT_FILE_ERROR` | 重置输入文件失败,可能导致输入污染。 |
| 5020 | `NAPI_ERROR_FUNCS` | 回调函数执行过程中发生错误(含 `doString` 语法错误)。 |
| 5021 | `NAPI_CHDIR_ERROR` | 切换工作目录失败,可能导致包搜索错误,日志写入路径错误等。 |
| 5022 | `NAPI_NOCHUNK_FOUND` | 没有找到待调用的函数。 |
## 管道模式 (Pipeline Mode)
这是该引擎的核心特性,允许数据在多个脚本间自动流转,无需在仓颉层进行手动传递。
### 调用规范
1. **脚本编写**:作为管道节点的 Lua 脚本,必须使用 Lua 的变长参数语法 `...` 来接收上一个节点传递的数据。
```lua
-- node_b.lua
local input = ...
return "处理结果: " .. input
```
2. **加载顺序(逆序)**利用栈的后进先出LIFO特性需按照执行顺序的**逆序**进行加载。
- 期望的执行顺序:`A` -> `B` -> `C`
- 仓颉侧加载顺序:
1. `runner.load("C.lua", "C")`
2. `runner.load("B.lua", "B")`
3. `runner.load("A.lua", "A")`
3. **触发执行**
- 首先执行初始脚本,将其返回值压入栈顶。
- 然后调用 `runScript("", "")`,引擎将自动调用栈顶下方的函数(即最后加载的脚本 `B`),并将栈顶数据作为参数传入。
- `B` 执行完毕后的返回值成为新的栈顶,等待下一次 `runScript` 调用。
### 运行时语义说明
- 当 `path` 非空时,脚本会先完成编译并压入内部栈,再进入执行阶段。
- 若脚本在编译阶段发生语法错误,当前实现返回 `NAPI_LOAD_FILE_ERROR`,详细信息可通过 `result()` 获取。
- 在 `require` / `package.path` 场景下,`runScript` 返回当前 Lua 栈顶字符串结果;若栈顶内容是模块解析路径,则会直接返回该路径字符串。
### 管道模式示例
```cangjie
// 1. 按逆序加载A -> B -> C
runner.load("./scripts/add_suffix.lua", "add_suffix") // 脚本 C: 添加后缀
runner.load("./scripts/to_upper.lua", "to_upper") // 脚本 B: 转大写
runner.load("./scripts/add_prefix.lua", "add_prefix") // 脚本 A: 添加前缀
// 2. 执行初始数据生成脚本
let initialData = runner.runScript("./scripts/generate_data.lua", "hello")
// 3. 依次触发管道节点
let afterA = runner.runScript("","")//数据经过A
let afterB = runner.runScript("", "") // 数据经过脚本 B (to_upper)
let finalResult = runner.runScript("", "") // 数据经过脚本 C (add_suffix)
println(finalResult) // 最终输出: [PREFIX] HELLO [SUFFIX]
```
## I/O 重定向机制
当配置了 `input`、`output` 回调以及 `pathio` 路径时Lua 的标准 I/O 将被重定向:
- **输出重定向**Lua 调用 `print` 或 `io.write` 时,内容会写入 `{pathio}` 目录下的临时文件,并触发仓颉侧的 `output` 回调。您可以在回调中实现自己的输出逻辑(如写入日志、发送网络消息等)。
- **输入重定向**Lua 调用 `io.read` 时,会触发仓颉侧的 `input` 回调。您需要在回调中准备并提供输入数据(例如从文件读取或返回模拟数据),供底层读取。
## doString 使用说明
`doString` 允许直接执行 Lua 代码字符串,而无需写入文件。
### 基本用法
```cangjie
let runner = LuaRunner()
// 执行简单表达式
let res = runner.doString("return 1 + 1")
println(res) // 输出: 2
// 设置全局变量并读取
let res2 = runner.doString("g = 42; return g")
println(res2) // 输出: 42
```
### 注意事项
- `doString` 要求代码执行后栈顶必须是**字符串类型**的返回值
- 若代码不返回字符串(如返回 `nil`、数字或无返回值),将抛出 `NAPI_SCRIPT_BAD_RET` (5011) 错误
- 若代码存在语法错误,将抛出 `NAPI_ERROR_FUNCS` (5020) 错误
- `doString` 与 `runScript` 共享同一个 Lua 状态机,全局变量和已加载的模块可互相访问