lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 12/11/2012 06:19 AM, steve donovan wrote:
Hi all,

A few people were interested in my neglected work on Go Lua bindings,
and so I felt I should push them out into the world, rough as they
are.
First off, from what I've looked at, this looks great. Would you have any issue with me getting some of your golua work pushed into aarzilli's fork (it seems to me to be the most actively maintained)? The only thing it really needs is the lua_pushcclosure/Callback code to be compatible (mostly, there are some other small changes like LGetMetaTable being part of the State struct as well to be made in luar.)

Also, this may be a good candidate to post to the go-nuts mailing list as well.

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