GopherLua Documentation

repository·master·Indexed 27 days ago

https://github.com/yuin/gopher-lua

GopherLua is a Lua 5.1+ VM and compiler implemented in Go, allowing developers to embed Lua scripting capabilities into Go applications. It supports Lua 5.2 goto statements, provides Go APIs for extensible semantics, and includes a standalone interpreter called glua. Key features include LState configuration, Go function integration, LUserData for custom types, and support for Go channels and context for termination.

Tokens
12.3K
Snippets
16
Records
97
Agent score
91%

What's inside GopherLua

  1. Overview of GopherLua

    master
    GopherLua is a Lua 5.1 VM and compiler (including the goto statement from Lua 5.2) written entirely in Go. It is designed to be a scripting language with extensible semantics, providing Go APIs to embed Lua scripting into Go host programs.
  2. Use Goroutines and Channels in GopherLua

    master

    An LState is not goroutine-safe. Use one LState per goroutine and communicate via Go channels. GopherLua provides LChannel to bridge Go channels into Lua.

    Restrictions: Do NOT send the following objects over channels: LThread (state), LFunction, LUserData, or a LTable with a metatable.

    Lua API for Channels:

    • channel.make([buf:int]) -> ch:channel
    • channel.select(case:table, ...) -> {index:int, recv:any, ok:bool}
    • ch:send(data:any)
    • ch:receive() -> ok:bool, data:any
    • ch:close()
  3. Install the glua standalone interpreter

    master

    GopherLua provides a standalone interpreter called glua which supports the same options as the standard Lua interpreter. You can install it using go get.

    go get github.com/yuin/gopher-lua/cmd/glua
  4. Create a Lua module in Go

    master

    You can create a Lua module by defining a Loader function in Go. This loader uses L.SetFuncs to register a map of LGFunction exports into a new table and then returns that table to Lua via L.Push.

    // mymodule.go
    func Loader(L *lua.LState) int {
        mod := L.SetFuncs(L.NewTable(), exports)
        L.SetField(mod, "name", lua.LString("value"))
        L.Push(mod)
        return 1
    }
    
    var exports = map[string]lua.LGFunction{
        "myfunc": myfunc,
    }
    
    // In your main.go, preload it:
    L.PreloadModule("mymodule", mymodule.Loader)
  5. Share compiled Lua bytecode between LStates

    master

    To save memory when multiple LState instances need to run the same script, compile the script once into a *lua.FunctionProto and use DoCompiledFile to run it in different states. This is safe because the bytecode is read-only.

    // Compile once
    proto, err := lua.Compile(chunk, filePath)
    
    // Run in multiple states
    func Example() {
        codeToShare, _ := CompileLua("mylua.lua")
        a := lua.NewState()
        b := lua.NewState()
        
        DoCompiledFile(a, codeToShare)
        DoCompiledFile(b, codeToShare)
    }
  6. Understand differences between Lua and GopherLua

    master

    When migrating from standard Lua to GopherLua, be aware of the following behavioral differences:

    Supported Features

    • Goroutines/Channels: GopherLua supports channel operations via a channel type. The channel table provides functions for these operations.
    • Lua 5.2 Syntax: Supports goto and ::label:: statements.
    • Environment Variables: Use os.setenv(name, value) to set environment variables.

    Unsupported or Modified Features

    • Unsupported Functions: string.dump, os.setlocale, lua_Debug.namewhat, and package.loadlib are not supported. Debug hooks are also unsupported.
    • Garbage Collection: collectgarbage does not take arguments and triggers garbage collection for the entire Go program.
    • File Buffering: file:setvbuf does not support line buffering.
    • Time: Daylight saving time is not supported.
  7. Extend GopherLua with User-Defined types (LUserData)

    master

    Use LUserData to wrap Go structs and expose them to Lua. This involves:

    1. Creating a metatable with a unique type name via L.NewTypeMetatable.
    2. Registering a constructor function (e.g., newPerson) that creates the LUserData, assigns the Go struct to ud.Value, and sets the metatable.
    3. Using L.CheckUserData in Go functions to retrieve the underlying struct.
    type Person struct {
        Name string
    }
    
    func newPerson(L *lua.LState) int {
        person := &Person{L.CheckString(1)}
        ud := L.NewUserData()
        ud.Value = person
        L.SetMetatable(ud, L.GetTypeMetatable("person"))
        L.Push(ud)
        return 1
    }
    
    // In Lua:
    // p = person.new("Steeve")
  8. Run Lua scripts in GopherLua

    master

    To use GopherLua, import the package and create a new state using lua.NewState(). You can execute Lua code directly from a string using L.DoString() or from a file using L.DoFile(). Always ensure you call L.Close() to release resources.

    import (
        "github.com/yuin/gopher-lua"
    )
    
    L := lua.NewState()
    defer L.Close()
    
    // Run from string
    if err := L.DoString(`print("hello")`); err != nil {
        panic(err)
    }
    
    // Run from file
    if err := L.DoFile("hello.lua"); err != nil {
        panic(err)
    }
  9. Configure LState initialization options

    master

    When creating an LState, use lua.Options to control library loading and error reporting:

    • SkipOpenLibs: If true, GopherLua will not open built-in libraries by default. You must manually open them using OpenXXX functions.
    • IncludeGoStackTrace: If true, GopherLua will include Go stack traces when panics occur.
  10. Configure Registry and Callstack size

    master

    You can tune the memory and performance of an LState by passing lua.Options to lua.NewState().

    • Registry: Controls stack storage for calling functions and temporary variables. You can set RegistrySize (initial), RegistryMaxSize (maximum), and RegistryGrowStep (increment size). If RegistryMaxSize is 0, it will not auto-grow.
    • Callstack: Controls maximum call depth.
      • Use CallStackSize to set the limit.
      • Use MinimizeStackMemory: true to enable auto-growing/shrinking (saves memory but has a small performance cost). If false, the stack is fixed at CallStackSize.
    L := lua.NewState(lua.Options{
       RegistrySize: 1024 * 20,
       RegistryMaxSize: 1024 * 80,
       RegistryGrowStep: 32,
       CallStackSize: 120,
       MinimizeStackMemory: true,
    })
    defer L.Close()
  11. Register the standard Lua 'base' library

    master
    To initialize a GopherLua state with the standard Lua 5.1 base library (including functions like print, type, load, etc.), call OpenBase(L) on your *LState. This function sets up the global environment _G, defines _VERSION, and registers the core Lua functions.