diff --git a/README.md b/README.md index 0d51ee3..eb59eb8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,186 @@ -# LuaCangjie_api +# Lua Runner for Cangjie + +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) +[![Lua](https://img.shields.io/badge/Lua-5.4-blue)](https://www.lua.org/) +[![Cangjie](https://img.shields.io/badge/Cangjie-SDK-orange)](https://cangjie-lang.cn/) + +Lua Runner for Cangjie 是一个专为仓颉语言设计的轻量级、高性能 Lua 脚本执行引擎。它通过 C FFI 桥接 C++,提供了稳定且易用的 Lua 虚拟机管理能力。 +**注:本项目是开发原生鸿蒙应用时产生的副产物,当前版本依然存在局限性与不足,请详细检查后再使用。** + +除了基础的脚本嵌入功能外,该引擎的核心特色在于支持一种独特的 **“栈式管道执行模式”**,能够实现脚本间的隐式参数传递,非常适合构建数据处理管道、游戏脚本系统或插件化架构。同时,它提供了完善的异常处理机制和灵活的 I/O 重定向功能。 + +## 特性 + +- **轻量级集成**:基于 Lua 5.4,通过 FFI 直接与仓颉语言交互,性能损耗小。 +- **栈式管道模式**:支持脚本间基于栈的数据隐式传递,实现类似函数式管道的调用链。 +- **I/O 重定向**:可自定义 Lua 标准输入/输出(`print`, `io.read`)的回调函数,支持文件交换目录重定向。 +- **模块化管理**:提供 `load` 和 `unload` 方法,支持按名称动态加载和卸载 Lua 脚本模块,避免全局污染。 +- **完善的异常处理**:定义了详细的错误码体系,通过 `LuaError` 类统一抛出,便于调试和逻辑控制。 +- **链式调用**:大部分操作方法返回实例本身,支持流畅的调用风格。 + +## 快速开始 + +### 环境要求 + +- Cangjie 语言环境 +- 底层 C++ 库(需要预先编译好与 Lua 5.4 链接的动态库) + +### 基本用法 + +```cangjie +import LuaCangjie_api.* + +main(): Int64 { + try { + // 1. 创建 Lua 运行实例 + let runner = LuaRunner() + + // 2. 加载一个脚本模块,命名为 "myScript" + runner.load("./scripts/hello.lua", "myScript") + + // 3. 执行脚本,传入参数 "World" + let result = runner.runScript("", "World") + println("Script result: ${result}") // 输出: Script result: Hello, World! + + + } catch (e: LuaError) { + println("Lua Error [${e.code}]: ${e.getMessage()}") + } + + return 0 +} +``` + +**脚本示例 (`hello.lua`)**: + +```lua +-- 使用 ... 接收从 runScript 传入的参数 +local name = ... +return "Hello, " .. name +``` + +## 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` 为空:触发**管道模式**,调用栈顶函数,并将栈顶数据作为参数传入。 | 脚本执行的字符串结果 | +| `clear(): This` | 清理 Lua 状态机,清空全局变量和所有加载的库,恢复到初始状态。 | 实例本身 (`This`) | +| `result(): String` | 获取最近一次 `runScript` 成功执行的返回值。 | 字符串 | +| `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` | 回调函数执行过程中发生错误。 | + +## 管道模式 (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` 调用。 + +### 管道模式示例 + +```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` 回调。您需要在回调中准备并提供输入数据(例如从文件读取或返回模拟数据),供底层读取。 + +## 当前局限性 + +- **数据类型限制**:当前版本在仓颉与 Lua 交互层仅支持**字符串**类型。虽然 Lua 内部可以处理复杂数据结构,但传递给仓颉或从仓颉传入时必须进行序列化/反序列化(如 JSON)。 +- **容量限制**:内部使用固定数组管理加载的库,上限为 **20 个**,超过将报错 `5016`。 +- **I/O 性能**:I/O 重定向依赖于文件系统交换,相对于纯内存交互存在微小的性能开销。 + +## 许可证 + +本项目基于 GPLv3 协议开源。这意味着您可以自由地使用、修改和分发本软件,但任何衍生作品也必须以相同的 GPLv3 协议开源。详情请参阅 [LICENSE](LICENSE) 文件。 -基于lua-capi的薄封装,用于以cangjie的形式调用lua解释器。外部调用无需关心资源回收。 \ No newline at end of file diff --git a/cjpm.toml b/cjpm.toml index d5e9a12..843cc32 100644 --- a/cjpm.toml +++ b/cjpm.toml @@ -1,16 +1,21 @@ [package] -name = "LuaCangjie_api" +name = "luacangjie_api" version = "0.0.1" description = "Lua C API bindings for Cangjie" -cjc-version = "0.49.1" +# 【修正】更新为您的实际编译器版本 +cjc-version = "1.1.0" license = "GPLv3" -output-type ="executable" +output-type ="dynamic" + [dependencies] +# 【修正】显式声明测试依赖,版本号与 cjc-version 一致 +[test-dependencies] + [ffi.c] luacjapi.path = "./lib/build" [scripts] pre-build = "cjpm run build.cj pre-build" post-build = "cjpm run build.cj post-build" -pre-clean = "cjpm run build.cj pre-clm ean" \ No newline at end of file +pre-clean = "cjpm run build.cj pre-clean" diff --git a/lib/lua_runner.cpp b/lib/lua_runner.cpp index 005f2cf..068726e 100755 --- a/lib/lua_runner.cpp +++ b/lib/lua_runner.cpp @@ -153,7 +153,7 @@ int Lua_runner::clean()//进行新一轮调用前一定要先clean清除上个 " end " "end"; - luaL_dostring(this->L, clean_globals_code); + luaL_dostring(this->L, clean_globals_code);//清空全局变量 luaL_dostring(this->L, "package.loaded = {}");//清空当前引用的包 for(int i = 0 ;ipkg_cont;i++) { @@ -165,6 +165,7 @@ int Lua_runner::clean()//进行新一轮调用前一定要先clean清除上个 return 0; } +//TODO 支持更多类型的参数 int Lua_runner::run(const char *path,const char *arg) { if(!this->check_luastatue()) @@ -219,8 +220,10 @@ int Lua_runner::run(const char *path,const char *arg) NO_RETURN: return 0; } - +//TODO 实现函数调用 achieve func call via file +/* int Lua_runner::callfunction() { - -} \ No newline at end of file + return 0; +} + */ \ No newline at end of file diff --git a/src/bridge.cj b/src/bridge.cj index 9756b28..4472929 100644 --- a/src/bridge.cj +++ b/src/bridge.cj @@ -1,4 +1,4 @@ -package LuaCangjie_api +package luacangjie_api // ==================== FFI底层 ==================== @@ -52,6 +52,7 @@ private func toString(ptr: CString): String { // ==================== 异常 ==================== +/// Lua运行时错误类 public class LuaError <: Exception { public let code: Int32 @@ -60,13 +61,13 @@ public class LuaError <: Exception { this.code = code } - // 便捷构造函数:只传入错误码,自动获取描述 + /// 便捷构造函数:只传入错误码,自动获取描述 public init(code: Int32) { super(getErrorMessage(code)) this.code = code } - // 根据错误码获取错误描述 + /// 根据错误码获取错误描述 public static func getErrorMessage(code: Int32): String { match (code) { case 5001 => "JSON file load failed" @@ -93,7 +94,7 @@ public class LuaError <: Exception { } } - // 获取当前错误的描述 + /// 获取当前错误的描述 public func getMessage(): String { getErrorMessage(this.code) } @@ -101,17 +102,20 @@ public class LuaError <: Exception { // ==================== 主类 ==================== +/// Lua运行管理类 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状态机 + /// 构造lua状态机 + /// + /// @param input 类型function 用于lua内部触发输入时的调用的回调函数 + /// @param output 类型function 用于lua内部触发输出时调用的回调函数 + /// @param pathio 重定向io输出到pathio路径下 + /// @param pkgpath 重定向lua状态机包搜索路径 + /// @throws LuaError 当初始化失败(句柄为空)时抛出 public init(input!: IOCallback = defaultIO, output!: IOCallback = defaultIO, pathio!: String = "", pkgpath!: String = "") { this.ioInput = input this.ioOutput = output @@ -138,6 +142,12 @@ public class LuaRunner { } } + /// 加载动态库 + /// + /// @param path 库路径 + /// @param name 库名称 + /// @return 当前实例 + /// @throws LuaError 当加载库失败时抛出 public func load(path: String, name: String): This { let pathPtr = toCStr(path) let namePtr = toCStr(name) @@ -150,12 +160,18 @@ public class LuaRunner { } if (result != 0) { - let errMsg = toString(unsafe { getresult(this.handle) }) - throw LuaError(unsafe { get_errno() }, errMsg) + // [修正] 直接使用错误码构造异常,复用 LuaError 的错误码转描述机制 + // 避免调用 getresult 读取未初始化的 C 层字符串 + throw LuaError(unsafe { get_errno() }) } return this } + /// 卸载动态库 + /// + /// @param name 库名称 + /// @return 当前实例 + /// @throws LuaError 当卸载库失败时抛出 public func unload(name: String): This { let namePtr = toCStr(name) let result = unsafe { unload_lib(this.handle, namePtr) } @@ -165,12 +181,18 @@ public class LuaRunner { } if (result != 0) { - let errMsg = toString(unsafe { getresult(this.handle) }) - throw LuaError(unsafe { get_errno() }, errMsg) + // [修正] 直接使用错误码构造异常,复用 LuaError 的错误码转描述机制 + throw LuaError(unsafe { get_errno() }) } return this } + /// 运行Lua脚本 + /// + /// @param path 脚本路径 + /// @param arg 传递给脚本的参数 + /// @return 脚本执行结果字符串 + /// @throws LuaError 当脚本运行出错时抛出 public func runScript(path: String, arg: String): String { let pathPtr = toCStr(path) let argPtr = toCStr(arg) @@ -189,10 +211,16 @@ public class LuaRunner { return this.cachedResult } + /// 获取缓存的结果 public func result(): String { this.cachedResult } + /// 获取错误信息 public func error(): String { toString(unsafe { getresult(this.handle) }) } + /// 清理Lua状态机资源 + /// + /// @return 当前实例 + /// @throws LuaError 当清理失败时抛出 public func clear(): This { let result = unsafe { cleanup(this.handle) } if (result != 0) { @@ -200,4 +228,4 @@ public class LuaRunner { } return this } -} \ No newline at end of file +} diff --git a/src/lua_runner_test.cj b/src/lua_runner_test.cj new file mode 100644 index 0000000..b57772d --- /dev/null +++ b/src/lua_runner_test.cj @@ -0,0 +1,176 @@ +package luacangjie_api + +import std.unittest.* +import std.fs.* + +let scriptsDir = "./test/scripts" + +// ==================== +// 1. 基础运行与参数测试 +// ==================== + +@Test +func testRunScript(): Unit { + let runner = LuaRunner() + let path = scriptsDir + "/simple_return.lua" + let res = runner.runScript(path, "") + @Expect(res, "hello") +} + +@Test +func testRunScriptWithArg(): Unit { + let runner = LuaRunner() + let path = scriptsDir + "/args_test.lua" + let res = runner.runScript(path, "world") + @Expect(res, "world") +} + +// ==================== +// 2. 异常处理测试 +// ==================== + +@Test +func testRunScriptSyntaxError(): Unit { + let runner = LuaRunner() + let path = scriptsDir + "/syntax_error.lua" + try { + runner.runScript(path, "") + fail("Should throw syntax error") + } catch (e: LuaError) { + @Expect(e.code, 5010) + } +} + +@Test +func testRunScriptRuntimeError(): Unit { + let runner = LuaRunner() + let path = scriptsDir + "/runtime_error.lua" + try { + runner.runScript(path, "") + fail("Should throw runtime error") + } catch (e: LuaError) { + @Expect(e.code, 5010) + } +} + +// ==================== +// 3. 库加载测试 +// ==================== + +@Test +func testLoadLib(): Unit { + let runner = LuaRunner() + let path = scriptsDir + "/mylib.lua" + runner.load(path, "mylib") +} + +@Test +func testLoadLibFileNotFound(): Unit { + let runner = LuaRunner() + try { + runner.load("/no/such/file.lua", "badlib") + fail("Should throw file not found error") + } catch (e: LuaError) { + @Expect(e.code, 5003) + } +} + +@Test +func testUnloadLib(): Unit { + let runner = LuaRunner() + let path = scriptsDir + "/mylib.lua" + runner.load(path, "mylib") + runner.unload("mylib") +} + +@Test +func testUnloadLibNotFound(): Unit { + let runner = LuaRunner() + try { + runner.unload("nosuchlib") + fail("Should throw exception") + } catch (e: LuaError) { + @Expect(e.code, 5012) + } +} + +// ==================== +// 4. 状态管理与数据交互 +// ==================== + +@Test +func testCleanup(): Unit { + let runner = LuaRunner() + let setPath = scriptsDir + "/set_global.lua" + let getPath = scriptsDir + "/get_global.lua" + + runner.runScript(setPath, "") + runner.clear() + let res = runner.runScript(getPath, "") + @Expect(res, "nil") +} + +@Test +func testCrossCallDataPassing(): Unit { + let runner = LuaRunner() + let setPath = scriptsDir + "/cross_call_set.lua" + let getPath = scriptsDir + "/cross_call_get.lua" + + runner.runScript(setPath, "") + let res = runner.runScript(getPath, "") + @Expect(res, "1,2,3") +} + +// ==================== +// 5. I/O 重定向测试 +// ==================== + +@Test +func testRedirectPrint(): Unit { + let runner = LuaRunner(pathio: "/tmp") + let path = scriptsDir + "/print_test.lua" + runner.runScript(path, "") +} + +@Test +func testRedirectIoWrite(): Unit { + let runner = LuaRunner(pathio: "/tmp") + let path = scriptsDir + "/io_write_test.lua" + runner.runScript(path, "") +} + +@Test +func testRedirectIoRead(): Unit { + // 1. 准备输入文件 + let inputFile = "/tmp/input" + + // [修正点]:移除了不存在的 option 参数。 + // File.writeTo 默认行为即为 CreateOrTruncate: + // 文件存在会截断(覆盖),不存在则创建。 + File.writeTo(inputFile, "MockInputData".toArray()) + + // 2. 运行测试 + let runner = LuaRunner(pathio: "/tmp") + let path = scriptsDir + "/io_read_test.lua" + + let res = runner.runScript(path, "") + @Expect(res, "MockInputData") +} + +// ==================== +// 6. 错误码与回调 +// ==================== + +@Test +func testErrorCodesMapping(): Unit { + @Expect(LuaError.getErrorMessage(5001), "JSON file load failed") + @Expect(LuaError.getErrorMessage(5002), "Memory allocation failed") + @Expect(LuaError.getErrorMessage(5010), "Script internal error, check result for details") + @Expect(LuaError.getErrorMessage(9999), "Unknown error") +} + +@Test +func testDefaultIOCallback(): Unit { + let result = unsafe { defaultIO() } + @Expect(result, 0) +} diff --git a/src/main.cj b/src/main.cj deleted file mode 100644 index 2534521..0000000 --- a/src/main.cj +++ /dev/null @@ -1,25 +0,0 @@ -package LuaCangjie_api - -// ==================== main ==================== - -main(): Int64 { - try { - let runner = LuaRunner(pathio:"test") - - 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 deleted file mode 100644 index e75154b..0000000 --- a/test.lua +++ /dev/null @@ -1 +0,0 @@ -print("hello world") \ No newline at end of file diff --git a/test/scripts/args_test.lua b/test/scripts/args_test.lua new file mode 100644 index 0000000..80cc10a --- /dev/null +++ b/test/scripts/args_test.lua @@ -0,0 +1 @@ +return (...) diff --git a/test/scripts/cross_call_get.lua b/test/scripts/cross_call_get.lua new file mode 100644 index 0000000..d904491 --- /dev/null +++ b/test/scripts/cross_call_get.lua @@ -0,0 +1 @@ +return table.concat(data, ',') diff --git a/test/scripts/cross_call_set.lua b/test/scripts/cross_call_set.lua new file mode 100644 index 0000000..fb82a06 --- /dev/null +++ b/test/scripts/cross_call_set.lua @@ -0,0 +1 @@ +data = {1,2,3} diff --git a/test/scripts/get_global.lua b/test/scripts/get_global.lua new file mode 100644 index 0000000..4df6493 --- /dev/null +++ b/test/scripts/get_global.lua @@ -0,0 +1 @@ +return tostring(g or 'nil') diff --git a/test/scripts/io_read_test.lua b/test/scripts/io_read_test.lua new file mode 100644 index 0000000..4ec6c3a --- /dev/null +++ b/test/scripts/io_read_test.lua @@ -0,0 +1,2 @@ +local s = io.read('*a') +return s diff --git a/test/scripts/io_write_test.lua b/test/scripts/io_write_test.lua new file mode 100644 index 0000000..af10ebe --- /dev/null +++ b/test/scripts/io_write_test.lua @@ -0,0 +1 @@ +io.write("Data from lua") diff --git a/test/scripts/mylib.lua b/test/scripts/mylib.lua new file mode 100644 index 0000000..bfe863a --- /dev/null +++ b/test/scripts/mylib.lua @@ -0,0 +1 @@ +function foo() return 42 end diff --git a/test/scripts/print_test.lua b/test/scripts/print_test.lua new file mode 100644 index 0000000..4cdeb3d --- /dev/null +++ b/test/scripts/print_test.lua @@ -0,0 +1 @@ +print("Hello Cangjie") diff --git a/test/scripts/runtime_error.lua b/test/scripts/runtime_error.lua new file mode 100644 index 0000000..6cadd45 --- /dev/null +++ b/test/scripts/runtime_error.lua @@ -0,0 +1 @@ +error("oops") diff --git a/test/scripts/set_global.lua b/test/scripts/set_global.lua new file mode 100644 index 0000000..38fae13 --- /dev/null +++ b/test/scripts/set_global.lua @@ -0,0 +1 @@ +g = 123 diff --git a/test/scripts/simple_return.lua b/test/scripts/simple_return.lua new file mode 100644 index 0000000..bb585d4 --- /dev/null +++ b/test/scripts/simple_return.lua @@ -0,0 +1 @@ +return "hello" diff --git a/test/scripts/syntax_error.lua b/test/scripts/syntax_error.lua new file mode 100644 index 0000000..45a6f03 --- /dev/null +++ b/test/scripts/syntax_error.lua @@ -0,0 +1 @@ +for i=1,10 print(i) end