func main() { var L *lua.State L = lua.NewState() defer L.Close() L.OpenLibs() // just to show we can catch the panic defer func() { fmt.Println("done") if x := recover(); x != nil { fmt.Printf("run time panic: %v", x) } }() // we can still catch the panic without this, // but it allows us to do some custom recovery currentPanicf := L.AtPanic(nil) currentPanicf = L.AtPanic(currentPanicf) newPanic := func(L1 *lua.State) int { fmt.Println("I AM PANICKING!!!") return currentPanicf(L1) } L.AtPanic(newPanic) //force a panic L.PushNil() L.Call(0, 0) }
// Push a Go value 'val' of type 't' on the Lua stack. func GoToLua(L *lua.State, t reflect.Type, val reflect.Value) { if t == nil { t = val.Type() } if t.Kind() == reflect.Ptr { t = t.Elem() } switch t.Kind() { case reflect.Float64: case reflect.Float32: { L.PushNumber(val.Float()) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: { L.PushNumber(float64(val.Int())) } case reflect.Uint, reflect.Uint8: { L.PushNumber(float64(val.Uint())) } case reflect.String: { L.PushString(val.String()) } case reflect.Bool: { L.PushBoolean(val.Bool()) } case reflect.Slice: { makeValueProxy(L, val, SLICE_META) } case reflect.Map: { makeValueProxy(L, val, MAP_META) } case reflect.Struct: { makeValueProxy(L, val, STRUCT_META) } default: { // fmt.Println("unhandled go type",t,t.Kind()) if val.IsNil() { L.PushNil() } else { makeValueProxy(L, val, INTERFACE_META) } } } }
// copy a Go slice to a Lua table func CopySliceToTable(L *lua.State, vslice reflect.Value) int { if vslice.IsValid() && vslice.Type().Kind() == reflect.Slice { n := vslice.Len() L.CreateTable(n, 0) for i := 0; i < n; i++ { L.PushInteger(i + 1) GoToLua(L, nil, vslice.Index(i)) L.SetTable(-3) } return 1 } else { L.PushNil() L.PushString("not a slice!") } return 2 }
// copy a Go map to a Lua table func CopyMapToTable(L *lua.State, vmap reflect.Value) int { if vmap.IsValid() && vmap.Type().Kind() == reflect.Map { n := vmap.Len() L.CreateTable(0, n) for _, key := range vmap.MapKeys() { val := vmap.MapIndex(key) GoToLua(L, nil, key) GoToLua(L, nil, val) L.SetTable(-3) } return 1 } else { L.PushNil() L.PushString("not a map!") } return 2 }
func copyMapToTable(L *lua.State) int { vmap := valueOf(unwrapProxy(L, 1)) if vmap.IsValid() && vmap.Type().Kind() == reflect.Map { n := vmap.Len() L.CreateTable(0, n) for _, key := range vmap.MapKeys() { GoToLua(L, nil, key) GoToLua(L, nil, vmap.MapIndex(key)) L.SetTable(-3) } return 1 } else { L.PushNil() L.PushString("not a map!") } return 2 }
// return the Lua table at 'idx' as a copied Go map. If 't' is nil then the map // type is map[string]interface{} func CopyTableToMap(L *lua.State, t reflect.Type, idx int) interface{} { if t == nil { t = reflect.TypeOf(tmap) } te, tk := t.Elem(), t.Key() m := reflect.MakeMap(t) L.PushNil() if idx < 0 { idx-- } for L.Next(idx) != 0 { // key at -2, value at -1 key := valueOf(LuaToGo(L, tk, -2)) val := valueOf(LuaToGo(L, te, -1)) m.SetMapIndex(key, val) L.Pop(1) } return m.Interface() }
func CopyTableToStruct(L *lua.State, t reflect.Type, idx int) interface{} { if t.Kind() == reflect.Ptr { t = t.Elem() } s := reflect.New(t) // T -> *T ref := s.Elem() L.PushNil() if idx < 0 { idx-- } for L.Next(idx) != 0 { key := L.ToString(-2) f := ref.FieldByName(key) if f.IsValid() { val := valueOf(LuaToGo(L, f.Type(), -1)) f.Set(val) } L.Pop(1) } return s.Interface() }
// Push a Go value 'val' of type 't' on the Lua stack. // If we haven't been given a concrete type, use the type of the value // and unbox any interfaces. func GoToLua(L *lua.State, t reflect.Type, val reflect.Value) { proxify := true if t == nil { t = val.Type() if t.Kind() == reflect.Interface { // unbox interfaces! val = valueOf(val.Interface()) t = val.Type() } proxify = false } if t.Kind() == reflect.Ptr { t = t.Elem() } switch t.Kind() { case reflect.Float64: case reflect.Float32: { L.PushNumber(val.Float()) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: { L.PushNumber(float64(val.Int())) } case reflect.Uint, reflect.Uint8: { L.PushNumber(float64(val.Uint())) } case reflect.String: { L.PushString(val.String()) } case reflect.Bool: { L.PushBoolean(val.Bool()) } case reflect.Slice: { if proxify { makeValueProxy(L, val, SLICE_META) } else { CopySliceToTable(L, val) } } case reflect.Map: { if proxify { makeValueProxy(L, val, MAP_META) } else { CopyMapToTable(L, val) } } case reflect.Struct: { makeValueProxy(L, val, STRUCT_META) } default: { if val.IsNil() { L.PushNil() } else { makeValueProxy(L, val, INTERFACE_META) } } } }