Search code examples
golua

How can I define a Lua function with gopher-lua that has a pre-defined table as param, where the Lua script can access the table within that function?


I know how to define a Go function and set it global (the Double example from the docs). But what, if the argument of this function should be a pre-defined table?

function calling_this_function_would_be_required(predefined_table)
  print(predefined_table["something"])
end

The IMAP server Dovecot does provide something like the above: https://doc.dovecot.org/configuration_manual/authentication/lua_based_authentication/#examples

And I would like to also provide pre-defined functions with a table (or even user data). But I really have no idea on how to achieve this.

Having a table set global is easy (L.SetGlobal(...)), but how do I add it to a expected function?

Adding some function in Go

func CallMe(L *lua.LState) {
    // How do I add a table as argument??
}

func Foo() {
    L := NewState()
    defer L.Close()

    t := L.NewTable()
    t.RawSetString("example", lua.LString("some_value"))

    // I do not want a global table. I would like an expected Lua function that has _this_ table as argument
    L.SetGlobal("predefined_table", t)

    // Not even sure with his...
    L.SetGlobal("calling_this_function_is_required", L.NewFunction©llMe)) 
}

If someone could enlight me a bit that would be great :-) Thanks in advance


Solution

  • Based on @koyaanisqatsi answer, I found out how to get things working in Go.

    Go code example:

    package main
    
    import (
        "fmt"
    
        "github.com/yuin/gopher-lua"
    )
    
    type Person struct {
        Name       string
        GivenName  string
        Street     string
        PostalCode string
        City       string
    }
    
    func main() {
        p := &Person{
            Name:       "Mustermann",
            GivenName:  "Max",
            Street:     "Sackgasse 19",
            PostalCode: "36304",
            City:       "Alsfeld",
        }
    
        L := lua.NewState()
        defer L.Close()
    
        if err := L.DoFile("sample.lua"); err != nil {
            panic(err)
        }
    
        t := L.NewTable()
        t.RawSetString("name", lua.LString(p.Name))
        t.RawSetString("given_name", lua.LString(p.GivenName))
        t.RawSetString("street", lua.LString(p.Street))
        t.RawSetString("postal_code", lua.LString(p.PostalCode))
        t.RawSetString("city", lua.LString(p.City))
    
        if err := L.CallByParam(lua.P{
            Fn:      L.GetGlobal("call_me"),
            NRet:    1,
            Protect: true,
        }, t); err != nil {
            panic(err)
        }
    
        ret := L.Get(-1) // returned value
        L.Pop(1)         // remove received value
    
        fmt.Println("The result of the Lua function is:", ret)
    }
    

    sample.lua file:

    function call_me(tbl)
        print(tbl.name)
        print(tbl.given_name)
        print(tbl.street)
        print(tbl.postal_code)
        print(tbl.city)
    
        return 0
    end
    

    Result:

    Mustermann
    Max
    Sackgasse 19
    36304
    Alsfeld
    The result of the Lua function is: 0