Skip to content

Instantly share code, notes, and snippets.

@niamster
Last active February 19, 2016 20:30
Show Gist options
  • Save niamster/4144a209ecfd6bb9dc6b to your computer and use it in GitHub Desktop.
Save niamster/4144a209ecfd6bb9dc6b to your computer and use it in GitHub Desktop.
calling lua scripts from goroutines
package main
import (
"github.com/yuin/gopher-lua"
"fmt"
)
const debug = false
const count = 10
func lstate() *lua.LState {
L := lua.NewState()
L.OpenLibs()
L.Register("go", goroutine)
L.SetGlobal("debug", debug && lua.LTrue || lua.LFalse)
L.SetGlobal("count", lua.LNumber(10))
return L
}
func goroutine(l *lua.LState) int {
fn := l.ToFunction(1)
vars := l.GetTop() - 1
values := make([]lua.LValue, vars)
for i := 0; i<vars; i += 1 {
values[i] = l.Get(i+2)
}
go func() {
L := lstate()
defer L.Close()
co := L.NewThread()
for {
st, err, values := L.Resume(co, fn, values...)
if st == lua.ResumeError {
fmt.Println("yield break(error)")
fmt.Println(err.Error())
break
}
if debug {
for i, lv := range values {
fmt.Printf("%v : %v\n", i, lv)
}
}
if st == lua.ResumeOK {
break
}
}
}()
return 0
}
func callLua(script string) interface{} {
L := lstate()
defer L.Close()
err := L.DoString(script)
if err != nil {
panic(err)
}
return L.ToInt(1)
}
func main() {
script := `
local ch = channel.make()
local t = { x = 3 }
for i = 1, count do
go(function(table)
if debug then print(table) end
assert(table.x == t.x, "table field")
ch:send(i)
coroutine.yield(i)
return i
end, t)
end
local sum = 0
local done = count
repeat
channel.select({"|<-", ch,
function(ok, data)
sum = sum + data
done = done - 1
end
})
until done == 0
ch:close()
return sum
`
res := callLua(script).(int)
expect := 0
for i := 1; i <= count; i += 1 {
expect += i
}
if res != expect {
panic(fmt.Sprintf("WTF? %d != %d", res, expect))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment