// return the Lua table at 'idx' as a copied Go slice. If 't' is nil then the slice // type is []interface{} func CopyTableToSlice(L *lua.State, t reflect.Type, idx int) interface{} { if t == nil { t = reflect.TypeOf(tslice) } te := t.Elem() n := int(L.ObjLen(idx)) slice := reflect.MakeSlice(t, n, n) for i := 1; i <= n; i++ { L.RawGeti(idx, i) val := LuaToGo(L, te, -1) slice.Index(i - 1).Set(valueOf(val)) L.Pop(1) } return slice.Interface() }
// Convert a Lua value 'idx' on the stack to the Go value of desired type 't'. Handles // numerical and string types in a straightforward way, and will convert tables to // either map or slice types. func LuaToGo(L *lua.State, t reflect.Type, idx int) interface{} { var value interface{} var kind reflect.Kind if t == nil { // let the Lua type drive the conversion... switch L.Type(idx) { case lua.LUA_TNIL: return nil // well, d'oh case lua.LUA_TBOOLEAN: kind = reflect.Bool case lua.LUA_TSTRING: kind = reflect.String case lua.LUA_TTABLE: kind = reflect.Interface default: return NewLuaObject(L, idx) } } else if t.Kind() == reflect.Ptr { kind = t.Elem().Kind() } else { kind = t.Kind() } switch kind { // various numerical types are tedious but straightforward case reflect.Float64: { ptr := new(float64) *ptr = L.ToNumber(idx) value = *ptr } case reflect.Float32: { ptr := new(float32) *ptr = float32(L.ToNumber(idx)) value = *ptr } case reflect.Int: { ptr := new(int) *ptr = int(L.ToNumber(idx)) value = *ptr } case reflect.Int8: { ptr := new(byte) *ptr = byte(L.ToNumber(idx)) value = *ptr } case reflect.String: { tos := L.ToString(idx) ptr := new(string) *ptr = tos value = *ptr } case reflect.Bool: { ptr := new(bool) *ptr = bool(L.ToBoolean(idx)) value = *ptr } case reflect.Slice: { // if we get a table, then copy its values to a new slice if L.IsTable(idx) { value = CopyTableToSlice(L, t, idx) } else { value = unwrapProxy(L, idx) } } case reflect.Map: { if L.IsTable(idx) { value = CopyTableToMap(L, t, idx) } else { value = unwrapProxy(L, idx) } } case reflect.Struct: { if L.IsTable(idx) { value = CopyTableToStruct(L, t, idx) } else { value = unwrapProxy(L, idx) } } case reflect.Interface: { if L.IsTable(idx) { // have to make an executive decision here: tables with non-zero // length are assumed to be slices! if L.ObjLen(idx) > 0 { value = CopyTableToSlice(L, nil, idx) } else { value = CopyTableToMap(L, nil, idx) } } else if L.IsNumber(idx) { value = L.ToNumber(idx) } else if L.IsString(idx) { value = L.ToString(idx) } else if L.IsBoolean(idx) { value = L.ToBoolean(idx) } else { value = unwrapProxy(L, idx) } } default: { fmt.Println("unhandled type", t) value = 20 } } return value }