rilua 0.1.13

Lua 5.1.1 implemented in Rust, targeting the World of Warcraft addon variant.
Documentation

rilua

A Rust implementation of Lua 5.1.1.

Discord Sponsor CI Status docs.rs Rust Version Crates.io Version License License

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
rilua script.lua

# Execute a string
rilua -e 'print("hello")'

# Interactive REPL
rilua -i

# All flags: -e stat, -l name, -i, -v, --, -
rilua -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
riluac -o output.luac script.lua

# List bytecode instructions
riluac -l script.lua

# Detailed listing (constants, locals, upvalues)
riluac -l -l script.lua

# Syntax check only
riluac -p script.lua

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 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)?;

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, numeric for, generic for, 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, xpcall with 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.dump and 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, \0 in 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)
  • __gc finalizers 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.loadlib returns (nil, msg, "absent") by default (incompatible ABI with PUC-Rio C modules). With the dynmod feature, package.loadlib loads rilua-native Rust modules. Lua file loading via require works 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:

mise install
# Build
cargo build

# Run the interpreter
cargo run -- script.lua

# Run tests
cargo test

# Run quality gate
cargo fmt -- --check && cargo clippy --all-targets && cargo test && cargo doc --no-deps

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:

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.