luazig is a reimplementation of Lua 5.5.0 in Zig, continuously validated against the PUC Lua reference implementation.
The goal is not to write a similar language, but to gradually achieve drop-in compatibility with PUC Lua: the same observable behavior on the official test suite, honest limitations, clean architecture, and a public Zig-facing embedding API.
- Implement Lua 5.5.0 in Zig with behavior as close as possible to PUC Lua.
- Pass the official upstream
testes/*.luasuite without test-specific hacks or harness workarounds. - Keep the reference implementation close at hand and compare
refvszigdirectly. - Develop a public Zig embedding API semantically close to the Lua C API.
- Use the current system Zig as the primary toolchain.
- Follow a PUC-first architectural approach when it does not lead to a clearly worse solution.
The project is in a pre-release / parity-focused state.
| Metric | Result |
|---|---|
Upstream matrix (testes/*.lua, --testc) |
31/32 pass (exit code parity) |
| Matrix non-pass | both_fail: big.lua |
Smoke tests (tests/smoke/*.lua) |
84/84 match (byte-identical stdout+stderr+exit) |
C API suites (tests/c_api) |
23 suites (gate: make -C tests/c_api test) |
Regression lane: python3 tools/testes_matrix.py --testc (no _port/_soft prelude overrides).
Geomean slowdown vs PUC Lua: 1.44x (measurement snapshot, runs=5 per workload; run-dependent diagnostic; lower is better; 1.0x = parity).
Gate protocol: paired-seed — 21 published seeds (1..21) per workload per session (LUAZIG_HASH_SEED env on the production ReleaseFast binary, pinned CPU core); verdict = per-seed paired instruction deltas; wall time is diagnostic only (tools/perf_compare.py). Latest gate verdict: OK (tools/perf/current-gate.json).
api580 anchored gate: GREEN — measured 384 B < 400 B; no-XY diagnostic: 436 B. Measured on the ReleaseFast binary 42de853aa3e35029; the ledger's top-level provenance is the Debug binary 788377ee8ee1ff1c (dual-mode ledger, not one single-RF-binary artifact). (tools/perf/current-api580-ledger.json). Charged/model totals 376/428 B (reconciled: false/false) are allocation-model charges, not measurements.
| Workload | Zig/PUC |
|---|---|
| metamethod_call_noalloc | 1.81x |
| array_access | 1.79x |
| field_access | 1.68x |
| hash_access | 1.66x |
| branch_loop | 1.65x |
| dynamic_load | 1.57x |
| global_arith | 1.54x |
| mixed_arith | 1.48x |
| coroutine_yield | 1.47x |
| float_arith | 1.43x |
| comparisons | 1.42x |
| metamethod_add | 1.37x |
| lua_calls | 1.36x |
| int_arith | 1.35x |
| table_alloc_setmetatable | 1.28x |
| temp_table_alloc | 1.17x |
| string_loop | 1.15x |
| string_concat | 1.09x |
See STATUS.md for detailed profiling methodology, hotspot analysis, and optimization history.
The bytecode VM (--vm=bc, default) is the only actively developed backend. The IR VM has been fully removed from the codebase.
zigfrom system toolchain.- C toolchain for reference Lua:
make,gccor compatible compiler. - Initialized upstream test suite submodule.
On Arch Linux:
sudo pacman -S --needed zig gcc makeVerify Zig:
zig versionInitialize submodule:
git submodule update --init --recursiveBuild the reference Lua in C:
make lua-c
./build/lua-c/lua -vBuild the Zig implementation:
zig build -Doptimize=ReleaseFast
./zig-out/bin/luazig --help
./zig-out/bin/luazigc --helpRun the full release gate:
tools/release_gate.shReference implementation:
./build/lua-c/lua./build/lua-c/luac
Zig implementation:
./zig-out/bin/luazig./zig-out/bin/luazigc
src/bin/ CLI entrypoints: luazig, luazigc
src/lua/ Language implementation: lexer, parser, AST, codegen, VM, stdlib, API
src/util/ Utility wrappers, including Zig std.Io stdio layer
lua-5.5.0/ Vendored PUC Lua 5.5.0: src/ (reference C) and testes/ (upstream test corpus)
tools/ Differential runners, release gate, perf tooling
tools/perf/ Core perf baselines and current snapshots
Runtime path:
src/lua/lexer.zig— reads source bytes, produces tokens.src/lua/parser.zig— builds AST.src/lua/codegen_bc.zig— compiles AST to bytecode (Proto).src/lua/vm.zig:runBytecode()— executes bytecode on a shared stack.src/lua/api.zig— public Zig-facing API and testC compatibility layer.src/lua/c_api.zig— C ABI (lua_*functions) for dlopen-based C extension loading.src/lua/dump.zig/src/lua/undump.zig— binary chunk serialization (string.dump/ load).
The test strategy is based on differential testing: the same upstream Lua test is run on both PUC Lua and luazig, then exit code and output are compared.
| Tool | Purpose |
|---|---|
tools/run_tests.py |
Targeted differential runner for specific suites |
tools/testes_matrix.py |
Per-file matrix over lua-5.5.0/testes/*.lua |
tools/testes_matrix.py --diff |
Adds normalized stdout comparison (detects behavioral differences even when exit codes match) |
tools/smoke_compare.py |
Runs tests/smoke/*.lua with both engines, compares stdout+stderr+exit byte-for-byte |
tools/api_regression_lane.py |
Zig unit/integration tests + testC lane |
tools/perf_compare.py |
Main perf gate: 18 micro-benchmarks, paired-seed instruction-delta regression check, geomean Zig/PUC ratio (diagnostic) |
tools/release_gate.sh |
Unified command for checking release readiness |
Run the regression matrix lane (the gate used in STATUS/commits; no prelude overrides):
python3 tools/testes_matrix.py --testcRun the matrix with differential output comparison:
python3 tools/testes_matrix.py --diffRun smoke tests:
python3 tools/smoke_compare.pyRun the perf gate:
python3 tools/perf_compare.py # run + compare vs baseline
python3 tools/perf_compare.py --no-build # skip rebuild
python3 tools/perf_compare.py --update-baseline # rewrite baselineThe regression lane (tools/testes_matrix.py --testc) runs each upstream test
without any prelude. The _port/_soft prelude is an opt-in mode (--port,
--soft flags) used by timing-oriented lanes such as tools/perf_core_snapshot.py:
_port=truedisables non-portable OS/shell/locale/filesystem checks._soft=truedisables or shortens resource-heavy branches.big.luaunder_softreturns early (if _soft then return 'a' end); standalone execution without_softrequires acoroutine.wrapharness (as inall.lua).
The quantitative Parity/Performance block at the top of this README is
generated from lane JSON reports by tools/status_summary.py --write-readme
(single source of truth — do not edit those numbers by hand).
The main command for checking the current state:
tools/release_gate.shIt runs:
zig build test -Doptimize=Debug- Official
testClane - Targeted parity suites
- Iterative dispatch stress under 1-MB host stack
- Full safe matrix
- Core perf snapshot + perf guard
Expected result: green on all correctness lanes (build/unit, testC, differential smoke, iterative-dispatch stress, and upstream matrix).
For development history, architectural decisions, detailed performance analysis, GC design, and the full work log, see STATUS.md.
Same license as PUC Lua (MIT).