wowemulation-dev/rilua

GitHub: wowemulation-dev/rilua

这是一个专为魔兽世界模拟生态构建的纯Rust实现的Lua 5.1.1解释器,提供零依赖、内存安全且易于嵌入的脚本执行环境。

Stars: 23 | Forks: 2

# rilua 用 Rust 实现的 [Lua 5.1.1](https://lua.org/manual/5.1/)。 [**在浏览器中试用 rilua**](https://wowemulation-dev.github.io/rilua/) -- 无需安装。
[![Discord](https://img.shields.io/discord/1394228766414471219?logo=discord&style=flat-square)](https://discord.gg/Jj4uWy3DGP) [![Sponsor](https://img.shields.io/github/sponsors/danielsreichenbach?logo=github&style=flat-square)](https://github.com/sponsors/danielsreichenbach) [![CI Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/328aca5ce5025354.svg)](https://github.com/wowemulation-dev/rilua/actions) [![docs.rs](https://img.shields.io/docsrs/rilua)](https://docs.rs/rilua) [![Rust Version](https://img.shields.io/badge/rust-1.92+-orange.svg)](https://www.rust-lang.org) [![Crates.io Version](https://img.shields.io/crates/v/rilua)](https://crates.io/crates/rilua) [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE-APACHE) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)
## 概述 rilua 是一个从头开始用 Rust 编写的 Lua 5.1.1 解释器。其目标是 与 PUC-Rio 参考解释器实现行为等价——执行的 Lua 代码必须产生完全相同的结果。 [WoW Emulation project](https://github.com/wowemulation-dev) 的一部分。 零外部依赖——仅使用 Rust 标准库。 ### 用途 rilua 专为 World of Warcraft 模拟生态系统而构建: - **插件开发与测试** -- 在游戏客户端之外运行和测试 WoW 插件, 而无需启动 WoW - **服务端脚本** -- 嵌入到私服模拟器(CMaNGOS、 TrinityCore、AzerothCore)中,用于脚本化战斗遭遇、任务和 NPC 行为 - **客户端 Lua 环境模拟** -- 复现 WoW 客户端的 Lua 沙盒,包括受限的 stdlib、污染系统以及 WoW 特有的 扩展(bit 库、字符串函数、全局别名) - **插件兼容性测试** -- 自动化测试工具,用于验证 插件是否符合 Lua 5.1.1 规范 它也可作为 Rust 应用的可嵌入式 Lua 5.1.1 解释器, 以及研究 Lua 内部的可读参考实现。 详情请参见 `docs/src/use-cases.md`。 ### 为什么选择 rilua 在对于嵌入而言重要的几个方面,rilua 与基于绑定的方案 [mlua](https://github.com/mlua-rs/mlua)(它通过 FFI 封装了 PUC-Rio 的 C 实现)存在显著差异: **无需 C 工具链。** rilua 拥有零外部依赖。将其 添加到项目只需在 Cargo.toml 中添加 `rilua = "0.1"` —— 无需 C 编译器、无需 系统库、无需 `pkg-config`、无需 vendored C 源码。mlua 会引入 7 个以上的运行时 crate 以及 C Lua 源码。 **核心中无 unsafe。** VM、垃圾回收器、编译器和所有 标准库包含零个 `unsafe` 块。所有 FFI 均隔离在 `platform.rs` 中。基于 arena 的 GC 使用代际索引(`GcRef` = 两个 `u32`),并在每次访问时进行验证——过期的引用会返回 错误,而不会导致内存损坏。mlua 承认包含“大量 unsafe 代码”以桥接 C 的 `longjmp` 和 Rust 的所有权模型。 **错误保留调用栈。** PUC-Rio 使用 `setjmp`/`longjmp` 进行 错误处理,这会在任何处理程序运行之前展开 C 栈。rilua 将错误作为 `Result` 传播。错误发生后 CallInfo 链保持 完整,因此可以从活动栈生成回溯。 RAII 析构函数正常触发——嵌入中不会泄露资源。 **结构化错误类型。** Rust 代码获得带有独立 `.source`、`.line`、`.message` 字段的 `LuaError::Syntax`,或带有 `.traceback: Vec` 的 `LuaError::Runtime`。 对错误变体进行模式匹配,而不是从字符串中解析 `"stdin:3: ')' expected"`。 **原生 WASM 支持。** rilua 可直接编译至 `wasm32-unknown-unknown`。 mlua 仅支持 `wasm32-unknown-emscripten`(需要 Emscripten 工具链),因为它链接了依赖 libc 的 C 源码。 **原生 Rust 模块而非 C 模块。** 启用 `dynmod` 功能后, `package.loadlib` 会加载根据 rilua 的 ABI 编译的 Rust `cdylib` crate。模块作者编写的是 Rust 而非 C。宿主会验证 `RiluaModuleInfo` 结构体以确保版本兼容,并将入口点调用 包裹在 `catch_unwind` 中以将 panic 转换为 Lua 错误。无需 原始指针操作,无需手动栈管理。 **无互斥锁开销的 Send。** rilua 的 `send` 功能通过观察 `GcRef` 值本质上是 `u32` 索引——天然满足 `Send`——使 `Lua: Send` 得以实现。 mlua 的 `send` 功能将整个 VM 包裹在可重入互斥锁中,即使在 单线程使用中也会增加每次操作的锁开销。 **GcRef 句柄可 Copy 且无生命周期。** 可将其存储在结构体中、 放入 HashMap,自由传递。有效性通过代际计数器在访问时 进行检查。mlua 句柄带有 `'lua` 生命周期且 不能超过 Lua 状态的借用期限。 **性能。** 在官方测试套件上,rilua 比 PUC-Rio 慢约 1.7 倍 (测试环境:AMD Ryzen 7 8840U,release 模式,10 次运行的中位数)。 对于 Lua 执行仅占总运行时间一部分的工作负载 (配置、脚本钩子、游戏逻辑),这种开销是微不足道的。 有关与 PUC-Rio、mlua 及其他实现的详细基准测试,请参阅 `docs/src/comparison.md`。 ### 为什么是 Lua 5.1.1 World of Warcraft 的插件系统使用 Lua 5.1.1。关键的 5.1 特性包括: `unpack` 是全局函数(在 5.2 中移至 `table.unpack`),所有数值均为 `f64` (5.3 添加了整数),无 `goto` 关键字(在 5.2 中添加)。参见 [Warcraft Wiki: Lua](https://warcraft.wiki.gg/wiki/Lua)。 ## 用法 ### 独立解释器 `rilua` 复现了 PUC-Rio 的 `lua` 命令行界面: ``` # 运行 Lua 脚本 rilua script.lua # 执行字符串 rilua -e 'print("hello")' # 交互式 REPL rilua -i # 所有标志: -e stat, -l name, -i, -v, --, - rilua -v # Lua 5.1.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio ``` ### 字节码编译器 `riluac` 复现了 PUC-Rio 的 `luac` 字节码编译器和列表器: ``` # 编译为字节码 riluac -o output.luac script.lua # 列出字节码指令 riluac -l script.lua # 详细列表 (constants, locals, upvalues) riluac -l -l script.lua # 仅语法检查 riluac -p script.lua ``` 二进制块与 PUC-Rio 在两个方向上均交叉兼容。 ### 嵌入到 Rust 中 rilua 提供符合 Rust 习惯的 API,具有 `IntoLua`/`FromLua` 转换 trait(灵感来自 [mlua](https://github.com/mlua-rs/mlua)): ``` use rilua::{Lua, StdLib}; // Create interpreter with all standard libraries let mut lua = Lua::new_with(StdLib::ALL)?; // Execute Lua code lua.exec("x = 1 + 2")?; // Read and write globals with automatic type conversion let x: f64 = lua.global("x")?; assert_eq!(x, 3.0); lua.set_global("greeting", "hello")?; // Selective library loading for sandboxing let mut sandbox = Lua::new_with(StdLib::BASE | StdLib::STRING | StdLib::TABLE)?; ``` 完整 API 参考请参见 `docs/src/api.md`。 ## 支持的功能 ### 语言 实现了所有 Lua 5.1.1 语言功能: - 变量、赋值、局部声明 - 控制流:`if`/`elseif`/`else`、`while`、`repeat`/`until`、数值型 `for`、泛型 `for`、`break`、`return` - 函数:闭包、可变参数(`...`)、多返回值、尾调用、 方法语法(`obj:method()`) - 表:数组和哈希部分、构造器(`{1, 2, key = "val"}`) - 元表:全部 17 个元方法(`__index`、`__newindex`、`__call`、 `__add`、`__sub`、`__mul`、`__div`、`__mod`、`__pow`、`__unm`、`__eq`、 `__lt`、`__le`、`__concat`、`__len`、`__gc`、`__tostring`) - 字符串元表:方法语法(`("hello"):upper()`) - 协同程序:`create`、`resume`、`yield`、`wrap`、`status`、`running` - 环境:`setfenv`/`getfenv`、每个闭包的全局表 - 保护调用:带有错误对象和栈跟踪的 `pcall`、`xpcall` - 带有变量名的错误消息(匹配 PUC-Rio 格式) ### 标准库 全部 9 个标准库及其所有函数: | 库 | 函数 | 备注 | |---------|-----------|-------| | base | 29 | `print`、`assert`、`type`、`tostring`、`tonumber`、`pairs`、`ipairs`、`next`、`select`、`unpack`、`pcall`、`xpcall`、`error`、`loadstring`、`loadfile`、`dofile`、`load`、`setmetatable`、`getmetatable`、`rawget`、`rawset`、`rawequal`、`setfenv`、`getfenv`、`collectgarbage`、`newproxy`、`_G`、`_VERSION` | | string | 14 | `len`、`byte`、`char`、`sub`、`rep`、`reverse`、`lower`、`upper`、`format`、`find`、`match`、`gmatch`、`gsub`、`dump`。包含所有 Lua 5.1.1 功能的模式匹配。包含 `gfind` 别名。 | | table | 9 | `concat`、`insert`、`remove`、`sort`、`maxn`、`getn`、`setn`、`foreach`、`foreachi`。排序使用 PUC-Rio 的三数取中快速排序。 | | math | 28 | `abs` 到 `tanh`、`pi`、`huge`、`mod` 别名。 | | io | 18 | 11 个库函数 + 7 个文件方法。`stdin`/`stdout`/`stderr` 句柄。 | | os | 11 | `clock`、`date`、`difftime`、`execute`、`exit`、`getenv`、`remove`、`rename`、`setlocale`、`time`、`tmpname`。 | | debug | 14 | `getinfo`、`getlocal`、`setlocal`、`getupvalue`、`setupvalue`、`traceback`、`getregistry`、`getmetatable`、`setmetatable`、`getfenv`、`setfenv`、`gethook`、`sethook`、`debug`。 | | package | 9 | `require`、`module`、`loaded`、`preload`、`loaders`、`config`、`path`、`cpath`、`seeall`、`loadlib`。 | | coroutine | 6 | `create`、`resume`、`yield`、`wrap`、`status`、`running`。 | ### 字节码与兼容性 - 38 个基于寄存器的操作码,匹配 PUC-Rio 编码 - `string.dump` 和二进制块加载 - 二进制块与 PUC-Rio 交叉兼容(简单程序的字节级输出完全相同, 可双向加载) - 支持非 UTF-8 源文件(字符串字面量中的 `\255`、`\0`) ### 垃圾回收器 基于 arena 的增量式标记-清除,带有代际索引: - 5 状态增量回收(Pause、Propagate、SweepString、Sweep、 Finalize) - 写屏障(表为后向,上值为前向) - 带有错误传播的 `__gc` 终结器 - 弱表(`__mode` = "k"、"v" 或 "kv") - `collectgarbage()` API:collect、stop、restart、count、step、setpause、 setstepmul ## 已知限制 ### 尚未实现 - **`debug.debug()` 交互模式**:存根实现(立即返回)。 - **C 库加载**:`package.loadlib` 默认返回 `(nil, msg, "absent")` (与 PUC-Rio C 模块的 ABI 不兼容)。启用 `dynmod` 功能后,`package.loadlib` 加载 rilua 原生 Rust 模块。 通过 `require` 加载 Lua 文件在所有配置下均可工作。 ### 平台支持 rilua 可编译至 Linux、macOSWindows 和 `wasm32-unknown-unknown`。 所有 C FFI 均集中在 `src/platform.rs` 中,在 WASM 上使用纯 Rust 存根。 核心 VM、编译器和计算库(base、string、table、math、coroutine、debug)在所有平台上均可工作。I/O 和 OS 库需要文件系统,并在 WASM 上返回错误。 构建 WASM 目标请参阅 `docs/src/wasm.md`,浏览器演示源码请参阅 `examples/wasm-demo/`。 ### 平台说明 - **SIGINT 处理**:在 Unix 和 Windows 上,Ctrl+C 中断正在运行的代码。 第二次 Ctrl+C 立即终止。在其他平台(如 WASM)上无操作。 ### PUC-Rio 测试套件兼容性 所有 23 个官方 Lua 5.1.1 测试文件均通过,包括 `all.lua` 运行器,该运行器使用激进的 GC 设置顺序执行所有测试。 测试包括:api、attrib、big、calls、checktable、closure、code、constructs、 db、errors、events、files、gc、literals、locals、main、math、nextvar、 pm、sort、strings、vararg、verybig。 `all.lua` 运行器在约 3 秒内完成(release 模式)。 有关运行模式和比较脚本的详情,请参阅 `docs/src/testing.md`。 ## 架构 流水线:**Source -> Lexer -> Parser -> AST -> Compiler -> Proto -> VM** | 组件 | 描述 | |-----------|-------------| | Lexer | 带有单 token 预读的词法分析器,基于字节(`&[u8]`) | | Parser | 产生类型化 AST 的递归下降分析器 | | Compiler | 将寄存器字节码发送到 Proto 的 AST 遍历器 | | VM | 基于寄存器的调度,PUC-Rio 的 38 个操作码,CallInfo 链 | | GC | 基于 arena 的增量式标记-清除,写屏障,终结器 | | API | 基于 trait 的符合 Rust 习惯的嵌入(`IntoLua`/`FromLua`) | 设计文档请参阅 `docs/src/architecture.md`。 ## 构建 开发工具(Rust 1.92.0、markdownlint)可使用 [Mise](https://mise.jdx.dev/) 自动安装: ``` mise install ``` ``` # 构建 cargo build # 运行解释器 cargo run -- script.lua # 运行测试 cargo test # 运行质量门禁 cargo fmt -- --check && cargo clippy --all-targets && cargo test && cargo deny check && cargo doc --no-deps ``` ## 测试 五个测试层:编译器和 VM 模块内的单元测试、 集成测试(带有 `assert()` 的 Lua 脚本)、预言机比较 测试(相同的 Lua 代码在 rilua 和 PUC-Rio 中运行,比较输出)、 作为兼容性目标的 PUC-Rio 官方测试套件,以及 针对边缘情况的行为等价测试。 PUC-Rio 测试既可以单独通过,也可以通过 `all.lua` 运行器通过。 测试策略请参阅 `docs/src/testing.md`,官方测试 文档请参阅 [lua.org/tests/](https://lua.org/tests/)。 ## 致谢 - Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo 创造了 [Lua](https://lua.org) - Roblox 的 [Luau](https://github.com/luau-lang/luau) 团队展示了 大规模的基于 AST 的 Lua 编译 - [mlua](https://github.com/mlua-rs/mlua) 项目展示了符合 Rust 习惯的 Lua API 模式 - Matthew Orlando (cogwheel) 编写了 [lua-wow](https://github.com/cogwheel/lua-wow),记录了 WoW 客户端的 Lua 配置 ## 资源 - [Lua 5.1 参考手册](https://lua.org/manual/5.1/) - [PUC-Rio Lua 5.1.1 源码](https://github.com/lua/lua/tree/v5.1.1) - [Warcraft Wiki: Lua](https://warcraft.wiki.gg/wiki/Lua) ## 许可证 本项目在以下任一许可下双重授权: - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) 或 ) - MIT license ([LICENSE-MIT](LICENSE-MIT) 或 ) 您可以自行选择使用任一许可证。 ### 贡献 除非您明确声明,否则您有意提交以纳入本工作的任何贡献, 按照 Apache-2.0 许可证的定义,均将按上述方式双重授权,且不包含任何附加条款或条件。 **注意**:本项目与 Blizzard Entertainment 无关。它 是基于 World of Warcraft 模拟社区通过逆向工程实现的独立实现。
标签:AI工具, DNS解析, Emulation, Lua, Lua 5.1, Rust, WASM, WoW, 仿真, 可视化界面, 嵌入式脚本, 开源项目, 插件开发, 服务器脚本, 测试工具, 浏览器运行, 游戏开发, 游戏脚本, 编程语言, 网络流量审计, 解释器, 通知系统, 零依赖, 魔兽世界