mmcdole/lunar: A Lua 5.1 runtime for Go. Contribute to mmcdole/lunar development by creating an account on GitHub.

github.com · 2026-08-03 · by Long Nguyen ·github
A Lua 5.1 runtime for Go. Contribute to mmcdole/lunar development by creating an account on GitHub.

mmcdole/lunar

A Lua 5.1 runtime for Go. Contribute to mmcdole/lunar development by creating an account on GitHub.

5 stars · 0 forks · 0 watchers

README

Lunar

A fast, memory-efficient Lua 5.1 runtime for Go.

Lunar is a complete implementation of Lua 5.1 (plus 5.2-style goto and labels) in pure Go. The compiler, VM, and standard libraries are all tested against the reference implementation. Quick start package main

import ( "fmt"

"github.com/mmcdole/lunar" )

func main() { state, err := lua.New(lua.Options{Libraries: lua.CoreLibraries()}) if err != nil { panic(err) } defer state.Close()

results, err := state.DoString("@demo.lua", `return ("lunar"):upper()`) if err != nil { panic(err) }

text, _ := results[0].AsString() fmt.Println(text) // LUNAR } Libraries and file access are opt-in. lua.CoreLibraries() installs everything that can't touch the host, and lua.FullLibraries() adds IO, OS, and debug for scripts you trust. Loading scripts from disk is disabled until you configure a ScriptLoader. Calling Go from Lua NewNativeFunction wraps a Go function as a Lua value. Inside the callback, everything goes through the Frame: read arguments with its typed accessors, then return a result or throw a Lua error: // Callable from Lua as greet(name). greet, err := state.NewNativeFunction(func(frame lua.Frame) lua.Outcome { name, ok := frame.String(0) // first argument, must be a string if !ok { frame.ThrowArgTypeError(0, lua.StringKind) } return frame.ReturnString("hello, " + name) }) if err != nil { panic(err) } if err := state.SetGlobal("greet", greet.Value()); err != nil { panic(err) }

// results[0] is "hello, moon" results, err := state.DoString("@hello.lua", `return greet("moon")`) See Embedding Lunar for the full guide: calls, callbacks, tables, errors, cancellation, coroutines, and lifecycle. Performance Medians from 15 runs on an Apple M3 Pro with Go 1.25.1 at source revision 1d43aec. Lower is better.

Established Lua program Lunar GopherLua go-lua

binary-trees 162.2 ms 172.4 ms 179.8 ms

fannkuch-redux 23.63 ms 33.17 ms 40.14 ms

n-body 59.03 ms 193.39 ms 197.77 ms

spectral-norm 52.82 ms 160.14 ms 153.66 ms

Embedding operation Lunar GopherLua go-lua

Go calls Lua with scalar arguments 61.21 ns 61.51 ns 146.80 ns

Lua calls Go 1,000 times 62.49 µs 99.58 µs 84.37 µs

Lua echoes a 128-byte Go string 86.20 ns 81.41 ns 144.00 ns

Lua checksums a reused Go-built table 312.4 ns 578.3 ns 972.9 ns

Build a table in Go, then checksum it in Lua 2.230 µs 1.405 µs 1.645 µs

Loading a 9 MB CBOR graph Lunar GopherLua

Total memory allocated while loading 107.5 MB 784.6 MB

Live heap added after garbage collection 72.24 MiB 542.26 MiB

The full results include confidence intervals, allocation counts, and raw output; the benchmark protocol lists the commands, inputs, and runtime versions. Compatibility

Lunar GopherLua Shopify go-lua

Lua version Lua 5.1 with Lua 5.2-style goto Lua 5.1 with Lua 5.2-style goto Lua 5.2

Go API Functions return typed values; callbacks use typed Frame accessors Values are LValue objects; callbacks pass arguments and results through an LState stack Mirrors the Lua C API; values are addressed by numeric stack position

Libraries in a new state None by default; select any subset at construction or open one later All standard libraries None; call OpenLibraries or open them individually

Script-file loading Denied by default; select host files, an fs.FS, or a host function Ambient OS file access Ambient OS file access when the applicable libraries are open

Coroutines Supported from Lua and Go Supported from Lua and Go Not implemented

Cancellation One installed context covers execution, loading, and coroutines One context on the state, execution only No context-based cancellation

os.exit Returns an *lua.ExitRequest to Go Exits the entire Go process Exits the entire Go process

Binary chunks Reads and writes Lua 5.1 bytecode when byte order and type sizes match Cannot read or write standard Lua bytecode files Reads and writes Lua 5.2 bytecode through the Go API

Scope The compiler, VM, standard libraries, coroutines, binary chunks, weak tables, and finalizers are implemented. Current intentional limits:

no C ABI, native C-module loading, or light userdata; no debug.sethook or debug.gethook; garbage collection runs synchronously rather than incrementally; no deterministic VM-instruction budget; and no table-iteration helpers beyond the Table.Next primitive.

A State serves one goroutine at a time; separate States can run concurrently. The public embedding API is still stabilizing. Documentation

Embedding: setup, calls, callbacks, values, contexts, errors, and lifecycle Architecture: compiler, VM, runtime representation, and API boundaries Language compatibility: the goto extension and intentional Lua 5.1/5.2/LuaJIT choices Collection: Lua reachability, weak tables, and finalization Third-party notices: adapted algorithms, artwork, and benchmark sources

Lunar is available under the MIT License.

source

github.com · 3 images · 196 links

Comments (0)

No comments yet