Five Lua dialects and MacroLua in a single binary. A zero-dependency interpreter core, a Cranelift-backed trace JIT, ahead-of-time native compilation, and a sandbox designed for embedding untrusted scripts.
luna implements the Lua language family from the ground up in safe
Rust — no C, and no unsafe at the surface an embedder
touches. Pick the dependency footprint you want and grow into the JIT
and AOT tiers as your workload demands.
Every mainline Lua dialect in one build, selected per-Vm at construction. A single process can host several dialects concurrently without interference. MacroLua adds compile-time @macro expansion over the 5.4 surface.
luna-core pulls exactly one crate — itself. A cargo deny gate enforces it on every commit. That means a tiny audit surface, seconds-long builds, and a clean wasm32 target with no mmap RWX requirement.
A trace-based compiler in the LuaJIT lineage. Hot loops record into typed IR, lower through Cranelift, and run as native machine code — plugged in behind a trait so the interpreter path never depends on the backend.
luna-aot turns a Lua source file into a self-contained native executable — bytecode, warmed traces, and a static runtime linked into one binary that runs with luna nowhere on the host.
An mlua-shaped Lua facade, typed native functions with automatic argument decode, table builders, userdata via a derive macro, Rust-side coroutines and debug hooks, and structured LuaErrors.
The host owns the security boundary. Curated stdlib whitelisting, an instruction budget, an approximate memory cap, and bytecode loading off by default — every capability a script sees was opted in by Rust.
Compatibility is a measurement here, not a claim. A private corpus of 514 fixtures runs against stock PUC interpreters built from source — 5.1.5, 5.2.4, 5.3.6, 5.4.8 and 5.5.1 — and every one must match byte for byte, with zero skips, before a commit is green.
Compared on stdout, stderr and exit code against the reference binary for each dialect. CI additionally asserts the 5.5 interpreter is exactly 5.5.1, so the basis cannot drift with a runner image.
The upstream Lua test suite runs end-to-end across all five dialects with matching assert-count instrumentation — the same files PUC ships to validate its own releases.
AddressSanitizer over the full official suite nightly, Miri for provenance and UB, seven fuzz targets weekly behind a gate that fails on any crash artifact, and long-running soak with a sub-1% RSS drift bound.
Feature availability is driven by the capability predicates in
src/version.rs. luna emits per-dialect bytecode matching
PUC's compiler format, so PUC-compiled .luac files load
directly.
| Feature | 5.1 | 5.2 | 5.3 | 5.4 | 5.5 | MacroLua |
|---|---|---|---|---|---|---|
| Numeric | ||||||
Integer subtype Int | – | – | ✓ | ✓ | ✓ | ✓ |
// floor divide | – | – | ✓ | ✓ | ✓ | ✓ |
Bitwise & | ~ << >> | – | – | ✓ | ✓ | ✓ | ✓ |
Hex float 0x1p4 | – | ✓ | ✓ | ✓ | ✓ | ✓ |
| Syntax | ||||||
goto / ::label:: | – | ✓ | ✓ | ✓ | ✓ | ✓ |
Empty statement ; | – | ✓ | ✓ | ✓ | ✓ | ✓ |
| Strings | ||||||
\xXX / \z escapes | – | ✓ | ✓ | ✓ | ✓ | ✓ |
\u{XXXX} unicode escape | – | – | ✓ | ✓ | ✓ | ✓ |
| 5.4+ attributes | ||||||
local <const> | – | – | – | ✓ | ✓ | ✓ |
local <close> | – | – | – | ✓ | ✓ | ✓ |
| 5.5 exclusives | ||||||
global keyword | – | – | – | – | ✓ | – |
Named vararg function f(...name) | – | – | – | – | ✓ | – |
| MacroLua exclusives | ||||||
@name(args) compile-time macros | – | – | – | – | – | ✓ |
Full matrix, stdlib coverage, and the C API surface live in the compatibility reference.
luna ships as a Cargo workspace of seven published crates — three of them the ones you depend on directly. The interpreter core stands alone; the JIT and AOT tiers layer on top through a trait boundary, so removing or swapping the backend never touches the core API.
Lexer, parser, per-dialect compiler, dispatcher, runtime, stdlib, NaN-boxed values, an intrusive mark-sweep GC, the PUC pattern engine, and the JIT trait surface. Zero third-party crates.
The Cranelift-backed backend, a lua.h-compatible C ABI as cdylib / staticlib, the luna CLI, and the Lua embedding facade.
A build-time tool: Lua source → standalone native binary. Not a runtime dependency of what it produces.
Bump counter, check threshold.
Replay opcodes into typed IR.
Lower IR, register-allocate, emit.
Runs until a side-exit.
Add the crate that matches the footprint you want, construct a
Vm for the dialect you target, and evaluate.
// Cargo.toml → luna-jit = "3"
use luna_jit::{Vm, LuaVersion};
let mut vm = Vm::new(LuaVersion::Lua54);
let v = vm.eval("return 6 * 7")?; // [Int(42)]
For an interpreter with no third-party dependencies at all, depend on
luna-core instead. To produce a standalone native binary,
use luna-aot as a build-time tool. The
documentation covers the embedding API, the
sandbox controls, and the dialect matrix in full.