Skip to content

Repository files navigation

luazig

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.

Project Goals

  • Implement Lua 5.5.0 in Zig with behavior as close as possible to PUC Lua.
  • Pass the official upstream testes/*.lua suite without test-specific hacks or harness workarounds.
  • Keep the reference implementation close at hand and compare ref vs zig directly.
  • 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.

Current Status

The project is in a pre-release / parity-focused state.

Parity

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).

Performance

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.

Backend

The bytecode VM (--vm=bc, default) is the only actively developed backend. The IR VM has been fully removed from the codebase.

Requirements

  • zig from system toolchain.
  • C toolchain for reference Lua: make, gcc or compatible compiler.
  • Initialized upstream test suite submodule.

On Arch Linux:

sudo pacman -S --needed zig gcc make

Verify Zig:

zig version

Initialize submodule:

git submodule update --init --recursive

Quick Start

Build the reference Lua in C:

make lua-c
./build/lua-c/lua -v

Build the Zig implementation:

zig build -Doptimize=ReleaseFast
./zig-out/bin/luazig --help
./zig-out/bin/luazigc --help

Run the full release gate:

tools/release_gate.sh

Binaries

Reference implementation:

  • ./build/lua-c/lua
  • ./build/lua-c/luac

Zig implementation:

  • ./zig-out/bin/luazig
  • ./zig-out/bin/luazigc

Project Structure

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).

Testing

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.

Main test lanes

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

Common commands

Run the regression matrix lane (the gate used in STATUS/commits; no prelude overrides):

python3 tools/testes_matrix.py --testc

Run the matrix with differential output comparison:

python3 tools/testes_matrix.py --diff

Run smoke tests:

python3 tools/smoke_compare.py

Run 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 baseline

Interpreting results

The 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=true disables non-portable OS/shell/locale/filesystem checks.
  • _soft=true disables or shortens resource-heavy branches.
  • big.lua under _soft returns early (if _soft then return 'a' end); standalone execution without _soft requires a coroutine.wrap harness (as in all.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).

Release Gate

The main command for checking the current state:

tools/release_gate.sh

It runs:

  • zig build test -Doptimize=Debug
  • Official testC lane
  • 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).

Detailed Status

For development history, architectural decisions, detailed performance analysis, GC design, and the full work log, see STATUS.md.

License

Same license as PUC Lua (MIT).

About

lua in zig

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages