All notable changes to this project are documented here. The format is based on Keep a Changelog, and the project aims to follow Semantic Versioning.
luapure ports PUC-Lua; the Lua language version it targets is called out separately from the luapure release version.
- Track PUC-Lua 5.5 as it stabilizes upstream (see
ROADMAP.md). - Performance: keep narrowing the speed/allocation gap to the reference (see
ROADMAP.mdfor the current levers).
Tooling and security. No API or observable-behaviour change; conformance stays at 30/33.
- Continuous integration. A GitHub Actions workflow
(
.github/workflows/ci.yml) now gates every pull request and push tomain: gofmt →go vet→ race-enabled tests with coverage → the official Lua 5.4 conformance fixtures. CI-only hardening addsgovulncheck, a cross-platform build matrix (Linux/macOS/Windows), and an observational (non-gating) benchmark run.
- Minimum Go raised to 1.25.11.
govulncheckflagged four advisories in the go1.24.x standard library — GO-2026-5037 (crypto/x509), GO-2026-4971 (net), GO-2026-4602 (os), and GO-2026-4601 (net/url) — all fixed in go1.25.x. Bumping thegodirective pulls the patched standard library. - Version constant synced.
Version(exposed to Lua as_LUAPURE_VERSION, and reported by the debug MCP adapters) now tracks the release version; it had been left at0.1.0through the 0.1.1 release.
0.1.1 — 2026-06-29
Performance and documentation. No API or observable-behaviour change; conformance stays at 30/33.
- Performance — arithmetic hot path. Inlined the monomorphic arith/bit fast
paths (
OP_ADD/SUB/MUL, the bitwise ops, andOP_ADDI): replacing the shared function-pointer helpers with per-op variants lets the int/float ops inline as direct calls. A tight float loop drops from ~2.45× to ~2.2× PUC; the in-repoArithHeavyExecbenchmark is ~10% faster (benchstat, no allocation change). Behaviour is bit-identical. - Performance — pattern-match allocation.
string.find/match/gsubnow recycle theirmatchStatethrough async.Poolinstead of allocating one per call; pattern-heavy workloads drop ~17% byte churn and ~6% of allocations. (string.gmatchkeeps a per-call state — it escapes into the iterator.)
- Re-based the cross-engine benchmark table on steady-state runs: the
tree_build/string_buildworkloads are sized to ~100 ms+ so fixed costs no longer inflate the ratios. Refresheddocs/BENCHMARKS.md,README.md, andROADMAP.md(now ~1.2–1.3× on table/string, ~2.2× on a tight float loop). - Added a Contributor Covenant code of conduct, GitHub issue forms, and a pull request template.
0.1.0 — 2026-06-28
First release. Targets PUC-Lua 5.4.8.
- Engine. Pure-Go port of PUC-Lua 5.4.8: instruction set, single-pass lexer+parser+codegen (no AST), and the VM dispatch loop.
- Standard libraries. base, string (incl. patterns and
string.pack/unpack), table, math (xoshiro256** PRNG, bit-identical to PUC), os, io, coroutine, utf8, debug, andrequire/package. - Precompiled chunks. Dump/undump ported from
ldump.c/lundump.c; output is byte-identical toluac 5.4.8on a 64-bit little-endian host, and luapure loadsluacoutput and vice versa. - Embedding API. Table create/read/write, Go-callback argument checking
(
Check*/Opt*),ToValue/FromValueconversion, structured*LuaErrorwithValue()/Traceback(), userdata with metatables and uservalues, sandboxing (NewSandbox/RunWith), cooperative cancellation (SetContext), file loading (LoadFile/DoFile/CompileReader), and lifecycleClose. - Version identifiers.
luapure.Version/VersionString()and the Lua global_LUAPURE_VERSION("luapure 0.1.0 (Lua 5.4.8)");_VERSIONstays exactly "Lua 5.4" for PUC conformance. - Debugger. Breakpoint / step / pause core, exposed over the Model Context
Protocol (stdio + HTTP,
debugmcp) and the Debug Adapter Protocol (TCP,debugdap), with standalone binaries undercmd/. - Conformance. 30/33 of the official Lua 5.4 test files pass — the PASS-able
ceiling; the three remaining are structural won't-fixes (see
ROADMAP.md). - Docs. README with quickstart,
docs/FILEMAP.md(PUC↔Go map), runnable embedding examples,make doc/make doc-web.
Observable semantics still match PUC; these are structural:
- GC delegated to the Go runtime; weak tables via
weak.Pointer,__gcviaruntime.SetFinalizer+ a drain queue. Valueis a tagged struct, not NaN-boxing (Go's precise GC must follow pointers).- Errors unwind via
panic/recoverinstead oflongjmp. - Coroutines are goroutines handing off over channels.
- Configurable memory-limit caps stand in for PUC's malloc-failure path (Go cannot turn OOM into a catchable error).