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/) -- 无需安装。
` =
两个 `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 模拟社区通过逆向工程实现的独立实现。
[](https://discord.gg/Jj4uWy3DGP)
[](https://github.com/sponsors/danielsreichenbach)
[](https://github.com/wowemulation-dev/rilua/actions)
[](https://docs.rs/rilua)
[](https://www.rust-lang.org)
[](https://crates.io/crates/rilua)
[](LICENSE-APACHE)
[](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标签:AI工具, DNS解析, Emulation, Lua, Lua 5.1, Rust, WASM, WoW, 仿真, 可视化界面, 嵌入式脚本, 开源项目, 插件开发, 服务器脚本, 测试工具, 浏览器运行, 游戏开发, 游戏脚本, 编程语言, 网络流量审计, 解释器, 通知系统, 零依赖, 魔兽世界