Go wrapper for LuaJIT.
Go to file
2025-02-12 19:17:11 -06:00
vendor/luajit Update libraries to use statically-linked amalgamated LuaJIT libraries. 2025-02-02 16:02:45 -06:00
.gitignore Update libraries to use statically-linked amalgamated LuaJIT libraries. 2025-02-02 16:02:45 -06:00
bytecode_test.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
bytecode.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
DOCS.md update readme, add docs 2025-02-02 18:55:22 -06:00
functions_test.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
functions.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
go.mod Add generate to the go.mod 2025-01-25 22:10:49 -06:00
LICENSE Initial commit 2025-01-21 12:35:06 -06:00
README.md Add bytecode compilation and execution, add benchmark 2025-02-03 10:41:05 -06:00
stack.go Add bytecode compilation and execution, add benchmark 2025-02-03 10:41:05 -06:00
table_test.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
table.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
types.go Implement the wrapper 2025-01-24 19:53:09 -06:00
wrapper_bench_test.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
wrapper_test.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00
wrapper.go BIG changes; no "safe" mode, function updates, etc 2025-02-12 19:17:11 -06:00

LuaJIT Go Wrapper

Hey there! This is a Go wrapper for LuaJIT that makes it easy to embed Lua in your Go applications. We've focused on making it both safe and fast, while keeping the API clean and intuitive.

What's This For?

This wrapper lets you run Lua code from Go and easily pass data back and forth between the two languages. You might want this if you're:

  • Adding scripting support to your application
  • Building a game engine
  • Creating a configuration system
  • Writing an embedded rules engine
  • Building test automation tools

Get Started

First, grab the package:

go get git.sharkk.net/Sky/LuaJIT-to-Go

You'll need LuaJIT's development files, but don't worry - we include libraries for Windows and Linux in the vendor directory.

Here's the simplest thing you can do:

L := luajit.NewSafe()
defer L.Close()
defer L.Cleanup()

err := L.DoString(`print("Hey from Lua!")`)

Stack Safety: Choose Your Adventure

One of the key decisions you'll make is whether to use stack-safe mode. Here's what that means:

Stack-Safe Mode (NewSafe())

L := luajit.NewSafe()

Think of this as driving with guardrails. It's perfect when:

  • You're new to Lua or embedding scripting languages
  • You're writing a server or long-running application
  • You want to handle untrusted Lua code
  • You'd rather have slightly slower code than mysterious crashes

The safe mode will:

  • Prevent stack overflows
  • Check types more thoroughly
  • Clean up after messy Lua code
  • Give you better error messages

Non-Stack-Safe Mode (New())

L := luajit.New()

This is like taking off the training wheels. Use it when:

  • You know exactly how your Lua code behaves
  • You've profiled your application and need more speed
  • You're doing lots of rapid, simple Lua calls
  • You're writing performance-critical code

The unsafe mode:

  • Skips most safety checks
  • Runs noticeably faster
  • Gives you direct control over the stack
  • Can crash spectacularly if you make a mistake

Most applications should start with stack-safe mode and only switch to unsafe mode if profiling shows it's necessary.

Working with Bytecode

Need even more performance? You can compile your Lua code to bytecode and reuse it:

// Compile once
bytecode, err := L.CompileBytecode(`
    local function calculate(x)
        return x * x + x + 1
    end
    return calculate(10)
`, "calc")

// Execute many times
for i := 0; i < 1000; i++ {
    err := L.LoadBytecode(bytecode, "calc")
}

// Or do both at once
err := L.CompileAndLoad(`return "hello"`, "greeting")

When to Use Bytecode

Bytecode execution is consistently faster than direct execution:

  • Simple operations: 20-60% faster
  • String operations: Up to 60% speedup
  • Loop-heavy code: 10-15% improvement
  • Table operations: 10-15% faster

Some benchmark results on a typical system:

Operation         Direct Exec    Bytecode Exec
----------------------------------------
Simple Math      1.5M ops/sec   2.4M ops/sec
String Ops       370K ops/sec   600K ops/sec
Table Creation   127K ops/sec   146K ops/sec

Use bytecode when you:

  • Have code that runs frequently
  • Need maximum performance
  • Want to precompile your Lua code
  • Are distributing Lua code to many instances

Registering Go Functions

Want to call Go code from Lua? Easy:

// This function adds two numbers and returns the result
adder := func(s *luajit.State) int {
    sum := s.ToNumber(1) + s.ToNumber(2)
    s.PushNumber(sum)
    return 1  // we're returning one value
}

L.RegisterGoFunction("add", adder)

Now in Lua:

result = add(40, 2)  -- result = 42

Working with Tables

Lua tables are pretty powerful - they're like a mix of Go's maps and slices. We make it easy to work with them:

// Go → Lua
stuff := map[string]interface{}{
    "name": "Arthur Dent",
    "age": 30,
    "items": []float64{1, 2, 3},
}
L.PushTable(stuff)

// Lua → Go
L.GetGlobal("some_table")
result, err := L.ToTable(-1)

Error Handling

We try to give you useful errors instead of mysterious panics:

if err := L.DoString("this isn't valid Lua!"); err != nil {
    if luaErr, ok := err.(*luajit.LuaError); ok {
        fmt.Printf("Oops: %s\n", luaErr.Message)
    }
}

A Few Tips

  • Always use those defer L.Close() and defer L.Cleanup() calls - they prevent memory leaks
  • Each Lua state should stick to one goroutine
  • For concurrent stuff, create multiple states
  • You can share functions between states safely
  • Keep an eye on your stack in unsafe mode - it won't clean up after itself
  • Start with stack-safe mode and measure before optimizing
  • Use bytecode for frequently executed code paths
  • Consider compiling critical Lua code to bytecode at startup

Need Help?

Check out the tests in the repository - they're full of examples. If you're stuck, open an issue! We're here to help.

License

MIT Licensed - do whatever you want with it!