yuin/gopher-lua
GopherLua: VM and compiler for Lua in Go
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5w ago
- ✓26+ active contributors
- ✓MIT licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 53% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/yuin/gopher-lua)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/yuin/gopher-lua on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: yuin/gopher-lua
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/yuin/gopher-lua shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 5w ago
- 26+ active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 53% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live yuin/gopher-lua
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/yuin/gopher-lua.
What it runs against: a local clone of yuin/gopher-lua — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in yuin/gopher-lua | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 67 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of yuin/gopher-lua. If you don't
# have one yet, run these first:
#
# git clone https://github.com/yuin/gopher-lua.git
# cd gopher-lua
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of yuin/gopher-lua and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "yuin/gopher-lua(\\.git)?\\b" \\
&& ok "origin remote is yuin/gopher-lua" \\
|| miss "origin remote is not yuin/gopher-lua (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "state.go" \\
&& ok "state.go" \\
|| miss "missing critical file: state.go"
test -f "vm.go" \\
&& ok "vm.go" \\
|| miss "missing critical file: vm.go"
test -f "parse/parser.go" \\
&& ok "parse/parser.go" \\
|| miss "missing critical file: parse/parser.go"
test -f "compile.go" \\
&& ok "compile.go" \\
|| miss "missing critical file: compile.go"
test -f "value.go" \\
&& ok "value.go" \\
|| miss "missing critical file: value.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 67 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~37d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/yuin/gopher-lua"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
GopherLua is a complete Lua 5.1 virtual machine and compiler implemented in pure Go, allowing you to embed Lua scripting directly into Go applications without CGo dependencies. It provides a user-friendly Go API (not stack-based like C Lua) for executing Lua code, defining Go functions callable from Lua, and managing execution state—solving the problem of needing scriptable, extensible Go programs without the complexity of C bindings. Single-package monolith: _state.go and _vm.go contain the core Lua state and virtual machine respectively; ast/ directory holds abstract syntax tree definitions (ast.go, expr.go, misc.go); parser, compiler, and standard library functions integrated throughout the root package. Tests live in _glua-tests/ (project-specific) and _lua5.1-tests/ (official test suite compliance).
👥Who it's for
Go developers building applications that need embedded scripting capabilities (game engines, configuration systems, plugin architectures) who want to avoid C/CGo complexity; also Lua enthusiasts wanting a pure-Go Lua implementation for education, cross-platform distribution, or integration with Go microservices.
🌱Maturity & risk
Actively maintained and production-ready. The project has comprehensive test coverage with both custom tests (_glua-tests/) and full Lua 5.1 compatibility tests (_lua5.1-tests/), CI/CD via GitHub Actions (test.yaml), and passes official Lua test suites. Based on file structure and test depth, this is a stable, well-tested implementation suitable for production use.
Low risk for a stable project: minimal dependencies (only github.com/chzyer/readline for the CLI tool), single primary maintainer (yuin), but the codebase is mature with no indication of abandonment. Main risk is Lua 5.1 is dated (released 2006)—if you need Lua 5.4 features, this won't help. No breaking changes appear imminent based on structure.
Active areas of work
Project appears stably maintained with no active breaking changes visible in structure. The test suite (_lua5.1-tests/) and CI pipeline (GitHub Actions test.yaml) suggest ongoing compatibility verification. No specific recent PRs or breaking milestones indicated in provided data, suggesting incremental maintenance mode rather than feature-active development.
🚀Get running
git clone https://github.com/yuin/gopher-lua.git
cd gopher-lua
go build -o gopher-lua ./cmd/gopher-lua
./gopher-lua # Interactive REPL
Or use as library: go get github.com/yuin/gopher-lua
Daily commands:
Development: make (Makefile present) or go test ./... to run test suite. Interactive: go run ./cmd/gopher-lua or build binary and run ./gopher-lua. Test: go test runs _glua-tests/ and _lua5.1-tests/ suites via test.yaml CI workflow.
🗺️Map of the codebase
state.go— Core VM state management and Lua execution environment initialization; entry point for embedding GopherLua into Go applications.vm.go— The virtual machine instruction executor; implements all opcode handling and runtime behavior for Lua script execution.parse/parser.go— Lua source code parser that converts text into an AST; critical for understanding how scripts are parsed before compilation.compile.go— AST-to-bytecode compiler; bridges parsing and VM execution by converting high-level constructs into opcodes.value.go— Lua value type system and representation; defines the fundamental data types and their behavior across the VM.table.go— Hash table implementation for Lua tables; core data structure used throughout the VM for associative arrays and metatables.ast/ast.go— Abstract syntax tree node definitions; provides the intermediate representation between parser and compiler.
🛠️How to make changes
Add a new Go function callable from Lua
- Define a Go function matching func(L *LState) int signature (
state.go) - Register in VM via SetGlobal() or package namespace (
baselib.go) - Push return values using L.Push*() and return count (
state.go) - Test via CallByParam() in Go or direct Lua script call (
script_test.go)
Add a new standard library module
- Create new file (e.g., newlib.go) with Lua module table builder functions (
mathlib.go) - Implement OpenNew() func that returns *LTable with Lua-callable functions (
baselib.go) - Register in linit.go OpenLibs() or as optional load via require() (
linit.go) - Add tests covering library functions (
_glua-tests/base.lua)
Add support for a new Lua language feature or opcode
- Define AST node type in ast/*.go (
ast/stmt.go) - Extend parser in parse/parser.go to recognize syntax (
parse/parser.go) - Add opcode(s) in opcode.go and emit code in compile.go (
compile.go) - Implement opcode handler in vm.go (
vm.go) - Validate with Lua 5.1 test suite (
_lua5.1-tests/all.lua)
Embed GopherLua in a Go application
- Import github.com/yuin/gopher-lua and create state with NewState() (
state.go) - Register Go functions via SetGlobal() or custom libraries via DoFile()/DoString() (
baselib.go) - Execute Lua via DoFile(), DoString(), or CallByParam() (
state.go) - Extract results using GetGlobal() and type-safe accessors (CheckString, OptInt) (
auxlib.go) - See cmd/glua/glua.go for a complete working example (
cmd/glua/glua.go)
🔧Why these technologies
- Go — Compile to single binary, excellent C-interop via cgo, memory safety, goroutine-based concurrency for Lua coroutines
- Lua 5.1 + goto (5.2) — Widely used embedded scripting language; 5.1 is stable and battle-tested; goto for power users
- Recursive descent parser — Simple, maintainable hand-written parser; easier to extend for new Lua features than yacc/bison
- Register-based bytecode VM — Lua standard; efficient instruction dispatch compared to stack VMs; matches C Lua semantics
⚖️Trade-offs already made
-
Pure Go implementation (no C bindings to official Lua)
- Why: Portability: single binary, no external dependencies; easier cross-compilation
- Consequence: Cannot directly reuse C extension modules; performance slower than C Lua (but still fast)
-
No JIT compilation
- Why: Complexity; focus on compatibility and correctness
- Consequence: Interpreted bytecode only; performance gap vs LuaJIT for hot code paths
-
Mark-and-sweep GC (via Go runtime)
- Why: Simplicity; leverage Go's GC; no manual cycle management
- Consequence: GC pauses; less predictable latency than Lua's incremental GC
-
One-pass compiler (AST → bytecode)
- Why: Fast startup; no IR/optimization passes
- Consequence: No compile-time optimizations; some runtime checks cannot be eliminated
🚫Non-goals (don't propose these)
- Does not implement Lua 5.3+ features (integers, bitwise ops, new metamethods)
- Not a real-time VM; GC pauses and goroutine scheduling not deterministic
- Does not support Lua C API FFI libraries (luajit.ffi); only pure Go extensions
- Not a source-code
🪤Traps & gotchas
No required env vars detected. Lua 5.1 semantics differ from modern Lua (no bitwise ops, different metatables)—users upgrading from Lua 5.3+ may hit compatibility issues. The _tools/go-inline tool exists but is not documented in README—check Makefile to understand its role in build process. Stack-based API design is explicitly NOT used here (opposite of C Lua), so C Lua cookbook examples won't directly translate.
🏗️Architecture
💡Concepts to learn
- Bytecode Compilation — GopherLua compiles Lua source to bytecode before execution in _vm.go—understanding this two-stage process (parser → compiler → VM execution) is essential for optimizing performance or debugging execution bugs
- Stack-free API Design — GopherLua explicitly rejects the C Lua stack-based API in favor of returning Go values directly; this architectural choice affects how you embed the VM and requires unlearning C Lua patterns
- Register-based VM — Unlike some interpreters, GopherLua's VM uses registers (not a pure stack model) for instruction execution, visible in _vm.go opcodes; this affects performance characteristics and bytecode layout
- LValue Interface — All Lua values (numbers, strings, tables, functions) implement the LValue interface in Go; understanding this polymorphism is critical for extending GopherLua or calling Go functions from Lua
- Lua Metatables and Metamethods — GopherLua implements Lua's metatable system for operator overloading and custom behavior; this is non-obvious and frequently misunderstood when embedding custom Go types
- Garbage Collection (Mark & Sweep) — The alloc.go file implements or interfaces with GC; understanding how GopherLua manages memory when embedding in Go is critical to avoid leaks or unsafe references across language boundaries
- Goroutine Integration — README mentions channel operations and goroutine support; GopherLua bridges Go concurrency primitives into Lua, a unique feature not in stock Lua that requires understanding both runtime models
🔗Related repos
lua/lua— Official Lua implementation in C; GopherLua reimplements its 5.1 spec, so understanding C Lua internals helps when debugging compatibility issuesmitchellh/gon— Go bindings to C Lua via CGo; alternative if you need newer Lua versions but accept CGo overheadShopify/go-lua— Another pure-Go Lua implementation; direct competitor with different design tradeoffs to compareyuin/gluamapper— Sibling project by same author that maps Go structs to Lua tables, commonly used alongside GopherLua for embeddingroblox/luau— Modern Lua variant used in production; shows where Lua evolved post-5.1 if GopherLua users need next-gen features
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive unit tests for auxlib.go helper functions
auxlib.go provides critical C API-like helper functions for Lua state manipulation (CheckInt, CheckString, CheckTable, etc.) but auxlib_test.go appears minimal. New contributors could expand test coverage for edge cases like type mismatches, nil values, and boundary conditions. This improves reliability for users depending on these utilities.
- [ ] Review existing tests in auxlib_test.go and identify untested functions
- [ ] Add table of test cases covering: valid inputs, type errors, nil values, and boundary cases
- [ ] Test helper functions like CheckOption, OptInt, OptString, OptTable with various input types
- [ ] Ensure error messages are validated
- [ ] Run tests with
make testto verify coverage
Add integration tests for coroutine library edge cases
The repo has coroutinelib.go and _glua-tests/coroutine.lua test file, but coroutinelib_test.go is missing entirely (not listed in file structure). Coroutines are complex and error-prone; dedicated Go unit tests would catch issues around resume/yield, status tracking, and panic handling that Lua tests might miss.
- [ ] Create coroutinelib_test.go with Go test cases
- [ ] Test coroutine creation, resume, yield, and status transitions
- [ ] Test error handling when resuming dead coroutines or invalid operations
- [ ] Test nested coroutine scenarios and panic recovery
- [ ] Add benchmarks for coroutine context switching overhead
Expand GitHub Actions workflow to test against multiple Go versions
The go.mod specifies Go 1.23, but .github/workflows/test.yaml likely tests only one version. Adding a matrix strategy to test against Go 1.21, 1.22, and 1.23 would catch compatibility regressions early, especially important for a widely-used library. This improves confidence for users on different Go versions.
- [ ] Review current .github/workflows/test.yaml configuration
- [ ] Add
strategy.matrix.go-version: ['1.21', '1.22', '1.23']to test job - [ ] Ensure tests run on Linux, macOS, and Windows (if not already)
- [ ] Verify test results pass across all Go versions
- [ ] Update README.md Installation section to document minimum supported Go version
🌿Good first issues
- Add test coverage for error handling in ast/expr.go—currently the AST tests focus on success paths; add tests for malformed expressions and type validation edge cases.
- Document the bytecode instruction set in a code comment block at the top of _vm.go—the opcodes are implemented but not formally documented, making VM changes risky for new contributors.
- Extend _glua-tests/issues.lua with regression tests for any reported GitHub issues—examine open issues (if any) and add tests to prevent future regressions in a systematic way.
⭐Top contributors
Click to expand
Top contributors
📝Recent commits
Click to expand
Recent commits
75f4976— docs: update README (yuin)b87eac2— chore: update test workflow (yuin)b59f85c— docs: convert README from rst to md (yuin)66d0cb7— chore: bump go version (yuin)ed5db76— Merge pull request #525 from BrightLocal/master (yuin)0d1d551— Merge pull request #523 from tul/disable_loadnil_merge (yuin)4911e39— PS-3239: error on too complex regex pattern (#1) (msoap)b3dcd3f— disable LOADNIL code generation optimisation (tul)ccacf66— Merge pull request #483 from serprex/gluabit32 (yuin)48fb8d7— Merge pull request #488 from Root-lee/fix-README-format-error (yuin)
🔒Security observations
The GopherLua codebase itself appears well-structured for a Lua VM implementation with no obvious code-level injection vulnerabilities in the examined file structure. However, the project has critical dependency management issues. All external dependencies are severely outdated (2018-2019), with the readline package being over 5 years old and golang.org/x/sys similarly aged. These outdated dependencies likely contain known security vulnerabilities that have been patched in newer versions. The Go version requirement (1.23) combined with ancient dependencies suggests incomplete maintenance. For a project used as an embedded scripting engine in other applications, this poses significant supply chain risk. Immediate dependency updates are essential before using this in production environments.
- High · Outdated Dependency: github.com/chzyer/readline —
go.mod - github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e. The readline dependency is pinned to version 0.0.0-20180603132655-2972be24d48e, which is from June 2018. This is over 5 years old and likely contains unpatched security vulnerabilities. The transitive dependencies (logex, test) are also extremely outdated. Fix: Update github.com/chzyer/readline to the latest version. Run 'go get -u github.com/chzyer/readline' and test thoroughly. Consider alternatives if the package is no longer maintained. - High · Outdated Transitive Dependencies —
go.mod - golang.org/x/sys v0.0.0-20190204203706-41f3e6584952. The golang.org/x/sys dependency is pinned to v0.0.0-20190204203706-41f3e6584952 (February 2019). This is over 4 years old and the sys package frequently contains critical security updates for system-level operations. Fix: Update golang.org/x/sys to the latest stable version. Run 'go get -u golang.org/x/sys' to ensure security patches are applied. - Medium · Go Version Compatibility —
go.mod - go 1.23. The go.mod specifies 'go 1.23', which is a very recent version. However, the dependencies are pinned to versions from 2018-2019 that may have compatibility issues with modern Go versions. This suggests potential maintenance gaps. Fix: Verify that all dependencies are compatible with Go 1.23. Run 'go mod tidy' and 'go test ./...' to ensure no breaking changes. Consider updating to maintained versions of all dependencies. - Low · Missing Security Policy —
.github/. While the repository has CONTRIBUTING.md and PULL_REQUEST_TEMPLATE.md, there is no visible SECURITY.md file defining a security vulnerability disclosure policy. Fix: Add a SECURITY.md file in the root or .github directory with a vulnerability disclosure process and security contact information.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.