//export GO_newindexObject func GO_newindexObject(_L unsafe.Pointer, ref unsafe.Pointer, lkey C.int, lvalue C.int) (ret int) { L := (*C.lua_State)(_L) node := (*refGo)(ref) vm := node.vm state := State{vm, L} v := reflect.ValueOf(node.obj) t := v.Type() k := v.Kind() defer func() { if r := recover(); r != nil { pushStringToLua(L, fmt.Sprintf("%v", r)) ret = -1 } }() ltype := C.lua_type(L, lkey) switch k { case reflect.Slice: if ltype == C.LUA_TNUMBER { tElem := t.Elem() value, err := state.luaToGoValue(int(lvalue), &tElem) if err != nil { panic(fmt.Sprintf("error when assign to slice member, %s", err.Error())) } idx := int(C.lua_tointeger(L, lkey)) v.Index(idx).Set(value) return 0 } panic(fmt.Sprintf("index of slice must be a number type, got `%v'", luaTypeName(ltype))) case reflect.Map: keyType := t.Key() key, err := state.luaToGoValue(int(lkey), &keyType) if err != nil { panic(fmt.Sprintf("index type of map must be type `%v', %s", keyType.Kind(), err.Error())) } if lvtype := C.lua_type(L, lvalue); lvtype == C.LUA_TNIL { v.SetMapIndex(key, reflect.Value{}) } else { tElem := t.Elem() value, err := state.luaToGoValue(int(lvalue), &tElem) if err != nil { panic(fmt.Sprintf("error when assign to map member, %s", err.Error())) } v.SetMapIndex(key, value) } return 0 case reflect.Ptr: if t.Elem().Kind() == reflect.Struct { _, err := state.setStructField(v, lkey, lvalue) if err != nil { panic(fmt.Sprintf("error when set field of struct, %s", err.Error())) } return 0 } } panic(fmt.Sprintf("try to assign a non-indexable go object, type `%v'", k)) return -1 }
func (self *Lua) RegisterFunction(name string, fun interface{}) { path := strings.Split(name, ".") name = path[len(path)-1] path = path[0 : len(path)-1] if len(path) == 0 { path = append(path, "_G") } // ensure namespaces for i, namespace := range path { cNamespace := cstr(namespace) if i == 0 { // top namespace what := C.lua_getglobal(self.State, cNamespace) if what == C.LUA_TNIL { // not exists C.lua_settop(self.State, -2) C.lua_createtable(self.State, 0, 0) C.lua_setglobal(self.State, cNamespace) C.lua_getglobal(self.State, cNamespace) } if C.lua_type(self.State, -1) != C.LUA_TTABLE { self.Panic("global %s is not a table", namespace) } } else { // sub namespace C.lua_pushstring(self.State, cNamespace) C.lua_rawget(self.State, -2) if C.lua_type(self.State, -1) == C.LUA_TNIL { C.lua_settop(self.State, -2) C.lua_pushstring(self.State, cNamespace) C.lua_createtable(self.State, 0, 0) C.lua_rawset(self.State, -3) C.lua_pushstring(self.State, cNamespace) C.lua_rawget(self.State, -2) } if C.lua_type(self.State, -1) != C.LUA_TTABLE { self.Panic("namespace %s is not a table", namespace) } } } // register function funcType := reflect.TypeOf(fun) if funcType.IsVariadic() { self.Panic("cannot register variadic function: %v", fun) } argc := funcType.NumIn() cName := cstr(name) function := &Function{ fun: fun, lua: self, name: name, funcType: funcType, funcValue: reflect.ValueOf(fun), argc: argc, } funcId := rand.Int63() functionRegister.Set(funcId, function) C.register_function(self.State, cName, (C.int64_t)(funcId)) self.Functions[name] = function C.lua_settop(self.State, -2) }
func packLuaObject(out io.Writer, state State, object int, depth int) (n int, err error) { L := state.L ltype := C.lua_type(L, C.int(object)) switch ltype { case C.LUA_TNUMBER: n, err = packLuaNumber(out, state, object) case C.LUA_TBOOLEAN: n, err = packLuaBoolean(out, state, object) case C.LUA_TSTRING: n, err = packLuaString(out, state, object) case C.LUA_TNIL: n, err = packLuaNil(out, state, object) case C.LUA_TTABLE: n, err = packLuaTable(out, state, object, depth) case C.LUA_TUSERDATA: fallthrough case C.LUA_TTHREAD: fallthrough case C.LUA_TLIGHTUSERDATA: fallthrough default: typeName := luaTypeName(ltype) return n, fmt.Errorf("cannot pack lua type `%v'", typeName) } return n, err }
func (state State) setStructField(structPtr reflect.Value, lkey C.int, lvalue C.int) (ret int, err error) { L := state.L vm := state.VM structValue := structPtr.Elem() t := structValue.Type() info := vm.findStruct(t) if info == nil { return -1, fmt.Errorf("can not assign field of a solid struct") } ltype := int(C.lua_type(L, lkey)) if ltype != C.LUA_TSTRING { return -1, fmt.Errorf("field key of struct must be a string") } key := stringFromLua(L, lkey) fld, ok := info.fields[key] if !ok { return -1, fmt.Errorf("not such field `%v'", key) } if fld.typ != DATA_FIELD { return -1, fmt.Errorf("only data field is assignble, but `%v' is not !", key) } sf := t.FieldByIndex(fld.dataIndex) // StructField value, err := state.luaToGoValue(int(lvalue), &sf.Type) if err != nil { return -1, err } structValue.FieldByIndex(fld.dataIndex).Set(value) return 0, nil }
func (state State) getStructField(structPtr reflect.Value, lkey C.int) (ret int, err error) { L := state.L vm := state.VM structValue := structPtr.Elem() t := structValue.Type() info := vm.findStruct(t) if info == nil { return -1, fmt.Errorf("can not index a solid struct") } ltype := int(C.lua_type(L, lkey)) if ltype != C.LUA_TSTRING { return -1, fmt.Errorf("field key of struct must be a string") } // //key := stringFromLua(L, lkey) //fld, ok := info.fields[key] // // <hack> using string pstr cache pstr := C.lua_tolstring(L, lkey, nil) // </hack> fld, ok := info.cache[pstr] if !ok { key := stringFromLua(L, lkey) return -1, fmt.Errorf("not such field `%v'", key) } value := getStructFieldValue(structValue, fld) state.goToLuaValue(value) return 1, nil }
// Pcall calls a lua function. no panic func (l *Lua) Pcall(fullname string, args ...interface{}) (returns []interface{}, err error) { C.push_errfunc(l.State) curTop := C.lua_gettop(l.State) // get function path := strings.Split(fullname, ".") for i, name := range path { if i == 0 { C.lua_getfield(l.State, C.LUA_GLOBALSINDEX, cstr(name)) } else { if C.lua_type(l.State, -1) != C.LUA_TTABLE { return nil, fmt.Errorf("%s is not a function", fullname) } C.lua_pushstring(l.State, cstr(name)) C.lua_gettable(l.State, -2) C.lua_remove(l.State, -2) // remove table } } if C.lua_type(l.State, -1) != C.LUA_TFUNCTION { return nil, fmt.Errorf("%s is not a function", fullname) } // args for _, arg := range args { l.pushGoValue(arg, "") } // call l.err = nil if ret := C.lua_pcall(l.State, C.int(len(args)), C.LUA_MULTRET, C.int(-(len(args))-2)); ret != 0 { // error occured return nil, fmt.Errorf("CALL ERROR: %s", C.GoString(C.lua_tolstring(l.State, -1, nil))) } else if l.err != nil { // error raise by invokeGoFunc return nil, l.err } else { // return values nReturn := C.lua_gettop(l.State) - curTop returns = make([]interface{}, int(nReturn)) for i := C.int(0); i < nReturn; i++ { value, err := l.toGoValue(-1-i, interfaceType) if err != nil { return nil, err } returns[int(nReturn-1-i)] = value.Interface() } } return }
func luaGetSubTable(L *C.lua_State, table C.int, key string) (bool, error) { pushStringToLua(L, key) C.lua_gettable(L, table) ltype := C.lua_type(L, -1) if ltype == C.LUA_TNIL { C.lua_createtable(L, 0, 0) // table[key] = {} pushStringToLua(L, key) C.lua_pushvalue(L, -2) C.lua_settable(L, table) } ltype = C.lua_type(L, -1) if ltype != C.LUA_TTABLE { C.lua_settop(L, -2) return false, fmt.Errorf("field `%v` exist, and it is not a table", key) } return true, nil }
//export GO_indexObject func GO_indexObject(_L unsafe.Pointer, ref unsafe.Pointer, lkey C.int) (ret int) { L := (*C.lua_State)(_L) node := (*refGo)(ref) vm := node.vm state := State{vm, L} v := reflect.ValueOf(node.obj) t := v.Type() k := v.Kind() defer func() { if r := recover(); r != nil { pushStringToLua(L, fmt.Sprintf("%v", r)) ret = -1 } }() ltype := C.lua_type(L, lkey) switch k { case reflect.Slice: if ltype == C.LUA_TNUMBER { idx := int(C.lua_tointeger(L, lkey)) value := v.Index(idx) state.goToLuaValue(value) return 1 } panic(fmt.Sprintf("index of slice must be a number type, here got `%v'", luaTypeName(ltype))) case reflect.Map: keyType := t.Key() key, err := state.luaToGoValue(int(lkey), &keyType) if err != nil { panic(fmt.Sprintf("index type of map must be type `%v', %s", keyType.Kind(), err.Error())) } value := v.MapIndex(key) if !value.IsValid() { C.lua_pushnil(L) return 1 } state.goToLuaValue(value) return 1 case reflect.Ptr: if t.Elem().Kind() == reflect.Struct { ret, err := state.getStructField(v, lkey) if err != nil { panic(fmt.Sprintf("error when get field of struct, %s", err.Error())) } return ret } } panic(fmt.Sprintf("try to index a non-indexable go object, type `%v'", k)) return -1 }
func (state *State) luaTableToKeyValues(ltable int) (value reflect.Value, err error) { var vvalue reflect.Value L := state.L size := sizeOfLuaTable(L, ltable) result := make([]base.KeyValue, 0, size) C.lua_pushnil(L) for { if 0 == C.lua_next(L, C.int(ltable)) { break } lvalue := int(C.lua_gettop(L)) lkey := lvalue - 1 vkey, err := state.luaToGoValue(lkey, nil) if err != nil { C.lua_settop(L, -3) // pop 2 break } if C.LUA_TTABLE == C.lua_type(L, C.int(lvalue)) { vvalue, err = state.luaTableToKeyValues(lvalue) } else { vvalue, err = state.luaToGoValue(lvalue, nil) } if err != nil { C.lua_settop(L, -3) // pop 2 break } key := vkey.Interface() var skey string if s, ok := key.(string); ok { skey = s } else { skey = fmt.Sprint(key) } value := vvalue.Interface() result = append(result, base.KeyValue{skey, value}) C.lua_settop(L, -2) // pop 1 } return reflect.ValueOf(result), err }
func mustBeMap(state State, lvalue int) *reflect.Value { var vmap *reflect.Value L := state.L ltype := C.lua_type(L, C.int(lvalue)) if ltype == C.LUA_TUSERDATA { ref := C.clua_getGoRef(L, C.int(lvalue)) if ref != nil { obj := (*refGo)(ref).obj objValue := reflect.ValueOf(obj) if objValue.Kind() == reflect.Map { vmap = &objValue } } } return vmap }
func (L *State) getValueByLuaType(i int) (v *rf.Value) { switch C.lua_type(L.s, C.int(i+1)) { case C.LUA_TBOOLEAN: v = L.getValueByType(rf.Bool, i) case C.LUA_TNUMBER: v = L.getValueByType(rf.Float64, i) case C.LUA_TSTRING: v = L.getValueByType(rf.String, i) case C.LUA_TUSERDATA: v = L.getValueByType(rf.Interface, i) default: L.pushString("Wrong parameters.") C.lua_error(L.s) v = nil } return }
// lua_isthread func (L *State) IsThread(index int) bool { return LuaValType(C.lua_type(L.s, C.int(index))) == LUA_TTHREAD }
// lua_istable func (L *State) IsTable(index int) bool { return LuaValType(C.lua_type(L.s, C.int(index))) == LUA_TTABLE }
// lua_isnoneornil func (L *State) IsNoneOrNil(index int) bool { return int(C.lua_type(L.s, C.int(index))) <= 0 }
// lua_isnone func (L *State) IsNone(index int) bool { return LuaValType(C.lua_type(L.s, C.int(index))) == LUA_TNONE }
// Returns true if the value at index is light user data func (L *State) IsLightUserdata(index int) bool { return LuaValType(C.lua_type(L.s, C.int(index))) == LUA_TLIGHTUSERDATA }
// Returns true if the value at index is user data pushed with PushGoFunction func (L *State) IsFunction(index int) bool { return LuaValType(C.lua_type(L.s, C.int(index))) == LUA_TFUNCTION }
// Returns true if lua_type == LUA_TBOOLEAN func (L *State) IsBoolean(index int) bool { return LuaValType(C.lua_type(L.s, C.int(index))) == LUA_TBOOLEAN }
// Returns the type of the value in the given valid index, or luajit.LUA_TNONE // for a non-valid index (that is, an index to an "empty" stack position). The // types returned by lua_type are coded by the following constants defined in // const.go: LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, // LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA. func (this *State) Type(index int) int { return int(C.lua_type(this.luastate, C.int(index))) }
//export golua_interface_newindex_callback func golua_interface_newindex_callback(Li interface{}, iid uint, field_name_cstr *C.char) int { L := Li.(*State) iface := L.registry[iid] ifacevalue := reflect.ValueOf(iface).Elem() field_name := C.GoString(field_name_cstr) fval := ifacevalue.FieldByName(field_name) if fval.Kind() == reflect.Ptr { fval = fval.Elem() } luatype := LuaValType(C.lua_type(L.s, 3)) switch fval.Kind() { case reflect.Bool: if luatype == LUA_TBOOLEAN { fval.SetBool(int(C.lua_toboolean(L.s, 3)) != 0) return 1 } else { L.PushString("Wrong assignment to field " + field_name) return -1 } case reflect.Int: fallthrough case reflect.Int8: fallthrough case reflect.Int16: fallthrough case reflect.Int32: fallthrough case reflect.Int64: if luatype == LUA_TNUMBER { fval.SetInt(int64(C.lua_tointeger(L.s, 3))) return 1 } else { L.PushString("Wrong assignment to field " + field_name) return -1 } case reflect.Uint: fallthrough case reflect.Uint8: fallthrough case reflect.Uint16: fallthrough case reflect.Uint32: fallthrough case reflect.Uint64: if luatype == LUA_TNUMBER { fval.SetUint(uint64(C.lua_tointeger(L.s, 3))) return 1 } else { L.PushString("Wrong assignment to field " + field_name) return -1 } case reflect.String: if luatype == LUA_TSTRING { fval.SetString(C.GoString(C.lua_tolstring(L.s, 3, nil))) return 1 } else { L.PushString("Wrong assignment to field " + field_name) return -1 } case reflect.Float32: fallthrough case reflect.Float64: if luatype == LUA_TNUMBER { fval.SetFloat(float64(C.lua_tonumber(L.s, 3))) return 1 } else { L.PushString("Wrong assignment to field " + field_name) return -1 } } L.PushString("Unsupported type of field " + field_name + ": " + fval.Type().String()) return -1 }
func (L *State) Type(index int) int { return int(C.lua_type(L.s, C.int(index))) }
func (L *State) IsNil(index int) bool { return int(C.lua_type(L.s, C.int(index))) == LUA_TNIL }
// lua_type func (L *State) Type(index int) LuaValType { return LuaValType(C.lua_type(L.s, C.int(index))) }
func (lua *Lua) toGoValue(i C.int, paramType reflect.Type) (ret reflect.Value) { luaType := C.lua_type(lua.State, i) paramKind := paramType.Kind() switch paramKind { case reflect.Bool: if luaType != C.LUA_TBOOLEAN { lua.Panic("not a boolean") } ret = reflect.ValueOf(C.lua_toboolean(lua.State, i) == C.int(1)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if luaType != C.LUA_TNUMBER { lua.Panic("not an integer") } ret = reflect.New(paramType).Elem() ret.SetInt(int64(C.lua_tointegerx(lua.State, i, nil))) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if luaType != C.LUA_TNUMBER { lua.Panic("not an unsigned") } ret = reflect.New(paramType).Elem() ret.SetUint(uint64(C.lua_tointegerx(lua.State, i, nil))) case reflect.Float32, reflect.Float64: if luaType != C.LUA_TNUMBER { lua.Panic("not a float") } ret = reflect.New(paramType).Elem() ret.SetFloat(float64(C.lua_tonumberx(lua.State, i, nil))) case reflect.Interface: switch luaType { case C.LUA_TNUMBER: ret = reflect.New(floatType).Elem() ret.SetFloat(float64(C.lua_tonumberx(lua.State, i, nil))) case C.LUA_TSTRING: ret = reflect.New(stringType).Elem() ret.SetString(C.GoString(C.lua_tolstring(lua.State, i, nil))) case C.LUA_TLIGHTUSERDATA: ret = reflect.ValueOf(C.lua_topointer(lua.State, i)) case C.LUA_TBOOLEAN: ret = reflect.New(boolType).Elem() ret.SetBool(C.lua_toboolean(lua.State, i) == C.int(1)) //TODO nil //TODO table default: lua.Panic("wrong interface argument: %v", paramKind) } case reflect.String: if luaType != C.LUA_TSTRING { lua.Panic("not a string") } ret = reflect.New(paramType).Elem() ret.SetString(C.GoString(C.lua_tolstring(lua.State, i, nil))) case reflect.Slice: switch luaType { case C.LUA_TSTRING: ret = reflect.New(paramType).Elem() cstr := C.lua_tolstring(lua.State, i, nil) ret.SetBytes(C.GoBytes(unsafe.Pointer(cstr), C.int(C.strlen(cstr)))) case C.LUA_TTABLE: ret = reflect.MakeSlice(paramType, 0, 0) C.lua_pushnil(lua.State) elemType := paramType.Elem() for C.lua_next(lua.State, i) != 0 { ret = reflect.Append(ret, lua.toGoValue(-1, elemType)) C.lua_settop(lua.State, -2) } default: lua.Panic("wrong slice argument") } case reflect.Ptr: if luaType != C.LUA_TLIGHTUSERDATA { lua.Panic("not a pointer") } pointer := C.lua_topointer(lua.State, i) ret = reflect.NewAt(paramType, unsafe.Pointer(&pointer)).Elem() case reflect.Map: if luaType != C.LUA_TTABLE { lua.Panic("not a map") } ret = reflect.MakeMap(paramType) C.lua_pushnil(lua.State) keyType := paramType.Key() elemType := paramType.Elem() for C.lua_next(lua.State, i) != 0 { ret.SetMapIndex( lua.toGoValue(-2, keyType), lua.toGoValue(-1, elemType)) C.lua_settop(lua.State, -2) } case reflect.UnsafePointer: ret = reflect.ValueOf(C.lua_topointer(lua.State, i)) //TODO complex64/128 //TODO array //TODO chan //TODO func //TODO struct default: lua.Panic("unknown argument type %v", paramType) } return }
func (state State) luaToGoValue(_lvalue int, outType *reflect.Type) (reflect.Value, error) { L := state.L lvalue := C.int(_lvalue) ltype := C.lua_type(L, lvalue) gkind := reflect.Invalid if outType != nil { gkind = (*outType).Kind() } switch ltype { case C.LUA_TNONE, C.LUA_TNIL: switch gkind { case reflect.Invalid, reflect.Func, reflect.Ptr, reflect.Interface: return reflect.ValueOf(nil), nil } case C.LUA_TBOOLEAN: switch gkind { case reflect.Invalid, reflect.Bool, reflect.Interface: cv := C.lua_toboolean(L, lvalue) var v bool if cv == 0 { v = false } else { v = true } return reflect.ValueOf(v), nil } //case C.LUA_TLIGHTUSERDATA: //case C.LUA_TTHREAD: case C.LUA_TNUMBER: switch gkind { case reflect.Int: v := int(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Int8: v := int8(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Int16: v := int16(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Int32: v := int32(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Int64: v := int64(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Uint: v := uint(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Uint8: v := uint8(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Uint16: v := uint16(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Uint32: v := uint32(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Uint64: v := uint64(C.lua_tointeger(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Float32: v := float32(C.lua_tonumber(L, lvalue)) return reflect.ValueOf(v), nil case reflect.Invalid, reflect.Interface, reflect.Float64: v := float64(C.lua_tonumber(L, lvalue)) return reflect.ValueOf(v), nil } case C.LUA_TSTRING: switch gkind { case reflect.Invalid, reflect.String, reflect.Interface: v := stringFromLua(L, lvalue) return reflect.ValueOf(v), nil } case C.LUA_TTABLE: if gkind == reflect.Slice && (*outType).Elem() == typeOfKeyValue { return state.luaTableToKeyValues(int(_lvalue)) } if gkind == reflect.Invalid || gkind == reflect.Interface || (outType != nil && *outType == reflect.TypeOf(theNullTable)) { tbl := state.NewLuaTable(int(lvalue)) return reflect.ValueOf(tbl), nil } case C.LUA_TFUNCTION: if gkind == reflect.Invalid || gkind == reflect.Interface || (outType != nil && *outType == reflect.TypeOf(theNullFunction)) { fn := state.NewLuaFunction(int(lvalue)) return reflect.ValueOf(fn), nil } case C.LUA_TUSERDATA: ref := C.clua_getGoRef(L, lvalue) if ref != nil { obj := (*refGo)(ref).obj objType := reflect.TypeOf(obj) objValue := reflect.ValueOf(obj) if gkind == reflect.Invalid || gkind == reflect.Interface { return objValue, nil } if outType != nil { if objType == *outType { return objValue, nil } if objType.Kind() == reflect.Ptr { if objType.Elem() == *outType { return objValue.Elem(), nil } } } } } return reflect.ValueOf(nil), fmt.Errorf("cannot convert from lua-type `%v' to go-type `%v'", luaTypeName(ltype), gkind) }
func (l *Lua) toGoValue(i C.int, paramType reflect.Type) (ret *reflect.Value, err error) { luaType := C.lua_type(l.State, i) paramKind := paramType.Kind() switch paramKind { case reflect.Bool: if luaType != C.LUA_TBOOLEAN { err = fmt.Errorf("not a boolean") return } v := reflect.ValueOf(C.lua_toboolean(l.State, i) == C.int(1)) ret = &v case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if luaType != C.LUA_TNUMBER { err = fmt.Errorf("not an integer") return } v := reflect.New(paramType).Elem() v.SetInt(int64(C.lua_tointeger(l.State, i))) ret = &v case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if luaType != C.LUA_TNUMBER { err = fmt.Errorf("not a unsigned") return } v := reflect.New(paramType).Elem() v.SetUint(uint64(C.lua_tointeger(l.State, i))) ret = &v case reflect.Float32, reflect.Float64: if luaType != C.LUA_TNUMBER { err = fmt.Errorf("not a float") return } v := reflect.New(paramType).Elem() v.SetFloat(float64(C.lua_tonumber(l.State, i))) ret = &v case reflect.Interface: switch paramType { case interfaceType: switch luaType { case C.LUA_TNUMBER: v := reflect.New(floatType).Elem() // always return float64 for interface{} v.SetFloat(float64(C.lua_tonumber(l.State, i))) ret = &v case C.LUA_TSTRING: v := reflect.New(stringType).Elem() v.SetString(C.GoString(C.lua_tolstring(l.State, i, nil))) ret = &v case C.LUA_TLIGHTUSERDATA, C.LUA_TUSERDATA: v := reflect.ValueOf(C.lua_touserdata(l.State, i)) ret = &v case C.LUA_TBOOLEAN: v := reflect.New(boolType).Elem() v.SetBool(C.lua_toboolean(l.State, i) == C.int(1)) ret = &v case C.LUA_TNIL: ret = nil default: err = fmt.Errorf("unsupported type %s for interface{}", luaTypeName(luaType)) return } default: err = fmt.Errorf("only interface{} is supported, no %v", paramType) return } case reflect.String: if luaType != C.LUA_TSTRING { err = fmt.Errorf("not a string") return } v := reflect.New(paramType).Elem() v.SetString(C.GoString(C.lua_tolstring(l.State, i, nil))) ret = &v case reflect.Slice: switch luaType { case C.LUA_TSTRING: v := reflect.New(paramType).Elem() cstr := C.lua_tolstring(l.State, i, nil) v.SetBytes(C.GoBytes(unsafe.Pointer(cstr), C.int(C.strlen(cstr)))) ret = &v case C.LUA_TTABLE: v := reflect.MakeSlice(paramType, 0, 0) C.lua_pushnil(l.State) elemType := paramType.Elem() for C.lua_next(l.State, i) != 0 { elemValue, e := l.toGoValue(-1, elemType) if e != nil { err = e return } // there is no nil value in lua table so elemValue will never be nil v = reflect.Append(v, *elemValue) C.lua_settop(l.State, -2) ret = &v } default: err = fmt.Errorf("wrong slice argument") return } case reflect.Ptr: if luaType != C.LUA_TLIGHTUSERDATA { err = fmt.Errorf("not a pointer") return } p := C.lua_topointer(l.State, i) v := reflect.NewAt(paramType, unsafe.Pointer(&p)).Elem() ret = &v case reflect.Map: if luaType != C.LUA_TTABLE { err = fmt.Errorf("not a map") return } v := reflect.MakeMap(paramType) C.lua_pushnil(l.State) keyType := paramType.Key() elemType := paramType.Elem() for C.lua_next(l.State, i) != 0 { keyValue, e := l.toGoValue(-2, keyType) if e != nil { err = e return } // table has no nil key so keyValue will not be nil elemValue, e := l.toGoValue(-1, elemType) if e != nil { err = e return } // table has no nil value so elemValue will not be nil v.SetMapIndex(*keyValue, *elemValue) C.lua_settop(l.State, -2) } ret = &v case reflect.UnsafePointer: v := reflect.ValueOf(C.lua_topointer(l.State, i)) ret = &v default: err = fmt.Errorf("unsupported toGoValue type %v", paramType) return } return }
// luaL_typename func (L *State) LTypename(index int) string { return C.GoString(C.lua_typename(L.s, C.lua_type(L.s, C.int(index)))) }
// Returns the type of the value in the given valid index, or Tnone for // a non-valid index (that is, an index to an "empty" stack position). The // types returned by lua_type are coded by the following constants defined in // const.go: Tnil, Tnumber, Tboolean, Tstring, Ttable, Tfunction, Tuserdata, // Tthread, and Tlightuserdata. func (s *State) Type(index int) int { return int(C.lua_type(s.l, C.int(index))) }