Firstly, direct bindings to Lua already exist - luago[1] has about 16
forks. I've contributed yet another fork[2], which doesn't use any
makefiles and is go-gettable, (with a caveat) This fork also provides
a way for bindings to use Go functions to define metatables, which
luar needed.
luago is pretty much a plain bridge to the C API and manages some of
the GC issues and so forth. luar attempts to go a bit further. Any Go
function can be made available to Lua scripts, without having to write
C-style wrappers. This can be done because Go has a powerful type
reflection system:
Here is a simple example:
package main
import "fmt"
import "strconv"
import "github.com/stevedonovan/luar"
func GoFun (args []int) (res map[string]int) {
res = make(map[string]int)
for i,val := range args {
res[strconv.Itoa(i)] = val*val
}
return
}
-- Go uses backticks for long strings - a little hard to see!
const code = `
print 'here we go'
--// Lua tables auto-convert to slices
local res = GoFun {10,20,30,40}
--// the result is a map-proxy
print(res['1'],res['2'])
--// which we may explicitly convert to a table
res = luar.map2table(res)
for k,v in pairs(res) do
print(k,v)
end
`
func main() {
L := luar.Init()
defer L.Close()
// arbitrary Go functions can be registered
// to be callable from Lua
luar.Register(L,"",luar.Map{
"GoFun":GoFun,
})
res := L.DoString(code)
if ! res {
fmt.Println("Error:",L.ToString(-1))
}
}
So a pretty arbitrary Go function is callable from Lua, and list-like
tables become slices on the Go side. The Go function returns a map,
which is wrapped as a proxy object. You can however then copy this to
a Lua table explicitly (there is also luar.slice2table)
Relevant to our discussion of using Lua as a configuration language in
Go programs, we can do this:
// an example of using Lua for configuration...
const setup = `
return {
baggins = true,
age = 24,
name = 'dumbo' ,
marked = {1,2},
options = {
leave = true,
cancel = 'always'
}
}
`
....
res = L.DoString(setup)
// there will be a table on the stack!
v := luar.CopyTableToMap(L,nil,-1)
fmt.Println("returned map",v)
m := v.(map[string]interface{})
for k,v := range m {
fmt.Println(k,v)
}
Again due to reflection, such structures can be traversed in Go in a
fairly straightforward way.
Now for the caveat: Linux distributions can never agree on the name of
the Lua library. Debian-derived uses -llua5.1, otherwise it's usually
just -llua. Since I currently know of no way to distinguish between
different kinds of Linux using the Go build tools, this golua version
will only 'just work' for Debian - otherwise go to luago.go in your
GOPATH and patch the link comment. (I've avoided the 'mobile header
location' problem by including the 5.1 include files)
So on Debian etc, 'go get github.com/stevedonovan/golua/lua51' will
not always work.
But 'go get github.com/stevedonovan/luar' should have no such problems
once golua is installed.
Or you can use the old-fashioned method and go to [3]
Next step is Lua 5.2!
steve d.
[1] https://github.com/afitz/golua
[2] https://github.com/stevedonovan/golua (fork #17!)
[3] https://github.com/stevedonovan/luar