rilua
A Rust implementation of Lua 5.1.1.
Overview
rilua is a from-scratch Lua 5.1.1 interpreter written in Rust. It targets behavioral equivalence with the PUC-Rio reference interpreter -- executed Lua code must produce identical results.
Part of the WoW Emulation project. Zero external dependencies -- only Rust's standard library.
Use Cases
rilua is built for the World of Warcraft emulation ecosystem:
- Addon development and testing -- Run and test WoW addons outside the game client without launching WoW
- Server-side scripting -- Embed in private server emulators (CMaNGOS, TrinityCore, AzerothCore) for scripted encounters, quests, and NPC behavior
- Client Lua environment emulation -- Reproduce the WoW client's Lua sandbox including restricted stdlib, taint system, and WoW-specific extensions (bit library, string functions, global aliases)
- Addon compatibility testing -- Automated test harness for verifying addons against the Lua 5.1.1 spec
It also serves as an embeddable Lua 5.1.1 interpreter for Rust applications
and as a readable reference implementation for studying Lua internals.
See docs/use-cases.md for details.
Why Lua 5.1.1
World of Warcraft's addon system uses Lua 5.1.1. Key 5.1-specific traits:
unpack is a global (moved to table.unpack in 5.2), all numbers are f64
(5.3 added integers), no goto keyword (added in 5.2). See
Warcraft Wiki: Lua.
Usage
Standalone Interpreter
rilua reproduces the PUC-Rio lua command-line interface:
# Run a Lua script
# Execute a string
# Interactive REPL
# All flags: -e stat, -l name, -i, -v, --, -
# Lua 5.1.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio
Bytecode Compiler
riluac reproduces the PUC-Rio luac bytecode compiler and lister:
# Compile to bytecode
# List bytecode instructions
# Detailed listing (constants, locals, upvalues)
# Syntax check only
Binary chunks are cross-compatible with PUC-Rio in both directions.
Embedding in Rust
rilua provides a Rust-idiomatic API with IntoLua/FromLua conversion
traits (inspired by mlua):
use ;
// Create interpreter with all standard libraries
let mut lua = new_with?;
// Execute Lua code
lua.exec?;
// Read and write globals with automatic type conversion
let x: f64 = lua.global?;
assert_eq!;
lua.set_global?;
// Selective library loading for sandboxing
let mut sandbox = new_with?;
See docs/api.md for the full API reference.
Supported Features
Language
All Lua 5.1.1 language features are implemented:
- Variables, assignments, local declarations
- Control flow:
if/elseif/else,while,repeat/until, numericfor, genericfor,break,return - Functions: closures, varargs (
...), multiple return values, tail calls, method syntax (obj:method()) - Tables: array and hash parts, constructors (
{1, 2, key = "val"}) - Metatables: all 17 metamethods (
__index,__newindex,__call,__add,__sub,__mul,__div,__mod,__pow,__unm,__eq,__lt,__le,__concat,__len,__gc,__tostring) - String metatable: method syntax (
("hello"):upper()) - Coroutines:
create,resume,yield,wrap,status,running - Environments:
setfenv/getfenv, per-closure global tables - Protected calls:
pcall,xpcallwith error objects and stack traces - Error messages with variable names (matching PUC-Rio format)
Standard Libraries
All 9 standard libraries with all functions:
| Library | Functions | Notes |
|---|---|---|
| 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. Pattern matching with all Lua 5.1.1 features. gfind alias included. |
| table | 9 | concat, insert, remove, sort, maxn, getn, setn, foreach, foreachi. Sort uses PUC-Rio's median-of-three quicksort. |
| math | 28 | abs through tanh, pi, huge, mod alias. |
| io | 18 | 11 library functions + 7 file methods. stdin/stdout/stderr handles. |
| 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. |
Bytecode and Compatibility
- 38 register-based opcodes matching PUC-Rio encoding
string.dumpand binary chunk loading- Binary chunks are cross-compatible with PUC-Rio (byte-identical output for simple programs, loadable in both directions)
- Non-UTF-8 source files supported (
\255,\0in string literals)
Garbage Collector
Arena-based incremental mark-sweep with generational indices:
- 5-state incremental collection (Pause, Propagate, SweepString, Sweep, Finalize)
- Write barriers (backward for tables, forward for upvalues)
__gcfinalizers with error propagation- Weak tables (
__mode= "k", "v", or "kv") collectgarbage()API: collect, stop, restart, count, step, setpause, setstepmul
Known Limitations
Not Yet Implemented
debug.debug()interactive mode: Stub (returns immediately).- C library loading:
package.loadlibreturns(nil, msg, "absent")by default (incompatible ABI with PUC-Rio C modules). With thedynmodfeature,package.loadlibloads rilua-native Rust modules. Lua file loading viarequireworks in all configurations.
Platform Notes
- SIGINT handling: Ctrl+C interrupts running code on Unix and Windows. Second Ctrl+C terminates immediately. No-op on other platforms (e.g. WASM).
PUC-Rio Test Suite Compatibility
All 23 official Lua 5.1.1 test files pass, including the all.lua
runner which executes all tests sequentially with aggressive GC settings.
Tests: api, attrib, big, calls, checktable, closure, code, constructs,
db, errors, events, files, gc, literals, locals, main, math, nextvar,
pm, sort, strings, vararg, verybig.
The all.lua runner completes in ~3 seconds (release mode).
See docs/testing.md for details on running modes and the comparison
script.
Architecture
Pipeline: Source -> Lexer -> Parser -> AST -> Compiler -> Proto -> VM
| Component | Description |
|---|---|
| Lexer | Tokenizer with one-token lookahead, byte-based (&[u8]) |
| Parser | Recursive descent producing typed AST |
| Compiler | AST walker emitting register-based bytecode into Proto |
| VM | Register-based dispatch, PUC-Rio's 38 opcodes, CallInfo chain |
| GC | Arena-based incremental mark-sweep, write barriers, finalizers |
| API | Trait-based Rust-idiomatic embedding (IntoLua/FromLua) |
See docs/architecture.md for design documentation.
Building
Development tools (Rust 1.92.0, markdownlint) can be installed automatically with Mise:
# Build
# Run the interpreter
# Run tests
# Run quality gate
&& && &&
Testing
Five test layers: unit tests inside compiler and VM modules,
integration tests (Lua scripts with assert()), oracle comparison
tests (same Lua code run in both rilua and PUC-Rio, comparing output),
the PUC-Rio official test suite as a compatibility target, and
behavioral equivalence tests for edge cases.
PUC-Rio tests pass both individually and through the all.lua runner.
See docs/testing.md for the testing strategy and
lua.org/tests/ for the official test
documentation.
Acknowledgments
- Roberto Ierusalimschy, Waldemar Celes, and Luiz Henrique de Figueiredo for Lua
- The Luau team at Roblox for demonstrating AST-based Lua compilation at scale
- The mlua project for Rust-idiomatic Lua API patterns
- Matthew Orlando (cogwheel) for lua-wow, documenting the WoW client's Lua configuration
Resources
Support the Project
If you find this project useful, please consider sponsoring the project.
This is currently a nights-and-weekends effort by one person. Funding goals:
- 20 hours/week - Sustained funding to dedicate real development time instead of squeezing it into spare hours
- Public CDN mirror - Host a community mirror for World of Warcraft builds, ensuring long-term availability of historical game data
Contributing
See the Contributing Guide for development setup and guidelines.
License
This project is dual-licensed under either:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
You may choose to use either license at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Note: This project is not affiliated with Blizzard Entertainment. It is an independent implementation based on reverse engineering by the World of Warcraft emulation community.