Expand description
luna-core — pure-Rust Lua runtime (interpreter only).
Zero third-party dependencies. The JIT-equipped variant lives in
the luna crate, which re-exports
everything here and additionally installs the Cranelift backend.
Primary dialect: Lua 5.5 (tracks official upstream). Compat modes: Lua 5.1 / 5.2 / 5.3 / 5.4.
§Threading model
vm::Vm is !Send + !Sync — one Vm per OS thread. The GC uses
raw NonNull<T> over an intrusive mark-sweep heap (not
reference-counted handles). Embedders wanting concurrency spawn
one Vm per worker thread and exchange data via channels; async
embedders use tokio::main(flavor = "current_thread") or a
LocalSet. See docs/threading.md for
canonical patterns and the post-v1.1 feature = "send" roadmap.
§Embedding contract (script-host sandbox)
The minimal embedding flow:
Vm::new_minimal(version)— empty VM, no libraries loaded, no JIT installed (the trait slots default to a no-op backend in luna-core).vm.open_base()/open_math()/open_string()/open_table()/open_coroutine()— whitelist only the safe subset; skipos/io/debug/package.vm.set_bytecode_loading(false)when running untrusted scripts (see caveats below).vm.set_instr_budget(Some(N))+vm.set_memory_cap(Some(M))per request.vm.load(src, name)→vm.call_value(closure, args).- On error:
vm.error_text(&e)+vm.take_error_traceback().
See examples/embed_min.rs for a runnable zero-dep walkthrough.
§Sandbox caveats
- JIT bypass of
instr_budget— the (optional) cranelift JIT compiles counted-for loops to native code that does not tick the budget. Sandbox embedders that link againstluna(notluna-core) must callvm.set_jit_enabled(false)before running untrusted scripts. - Bytecode load surface —
load()defaults to mode"bt"which accepts precompiled chunks, bypassing the parser’s depth/opcode limits. Sandbox embedders should callvm.set_bytecode_loading(false). instr_budget/mem_capare fire-once — both clear toNoneon first trip. Re-arm before eachcall_valueif reusing the Vm across requests, or (recommended) create a fresh Vm per request for isolation.heap.bytes()is approximate — internalVec/Boxcapacity overhead is not auto-tracked, so the cap is a lower bound. Size it with ~2× margin over the desired hard limit; bound the Vm’s lifetime as a second line of defense.error()may carry any Value — Lua scripts can callerror({code=…, msg=…})with a non-string payload. Usevm.error_text(&e)to normalize to a string, or inspecte.0directly when the host protocol expects structured errors.- Native panic = Vm-fatal — Rust panics in
NativeFncallbacks are caught and surfaced asLuaError("native panic: …"), but the Vm state may be inconsistent afterwards. Drop the Vm on any error whose text starts with"native panic:". - 5.1 / 5.2 lack
string.pack/unpack/packsize— these are 5.3+ additions, gated by version. 5.1 hosts (script host) see them asnilon thestringtable. - 5.1 numeric semantics — Lua 5.1 has no integer subtype.
Arithmetic and the
forloop always produceValue::Float; hosts that route results back through Rust must accept eitherInt(5.3+) orFloat(all versions). collectgarbage("count")is a timing channel — scripts can observe rough heap pressure changes. Acceptable for typical embedding; flag if the threat model includes side-channel probing.
Modules§
- compiler
- AST → bytecode compiler. Register model follows PUC lparser/lcode:
locals pin the low registers, temporaries grow from
freereg, constants are deduplicated, forward jumps are patch lists (plain Vecs instead of PUC’s in-code jump chains). Function nesting is a stack ofLevels; upvalue resolution walks it (PUC singlevaraux). - frontend
- Source → AST frontend (P01). Syntax only: scope resolution, constant folding and code generation live in later phases.
- jit
- luna-core JIT surface — trait + types only, zero Cranelift.
- numeric
- Lua numeral conversion core (stone candidate: pure functions, no runtime
types). Two consumers: the lexer (literal tokens, shape pre-validated by
scanning) and the VM/stdlib (
str2num— luaO_str2num semantics with whitespace and sign). Versioning is expressed as capability flags so this module stays dialect-agnostic. - pattern
- Lua pattern matching engine — a faithful port of lstrlib.c’s matcher. Pure functions over byte slices (stone candidate: no runtime types).
- runtime
- Runtime core: values, GC heap, strings, tables, function objects.
- version
- Lua dialect selection.
- vm
- Bytecode VM (P03): instruction set, errors, interpreter, builtins.