func (vm *VM) AddFunc(name string, fn interface{}) (bool, error) { value := reflect.ValueOf(fn) fnType := reflect.TypeOf(fn) if value.Kind() != reflect.Func { return false, fmt.Errorf("AddFunc only add function type") } _, err := checkFunc(fnType) if err != nil { return false, err } namePath := strings.Split(name, ".") baseName := namePath[len(namePath)-1] path := namePath[:len(namePath)-1] L := vm.globalL state := State{vm, L} if len(path) <= 0 { // _G[a] = fn pushStringToLua(L, baseName) state.pushObjToLua(fn) C.lua_settable(vm.globalL, C.LUA_GLOBALSINDEX) return true, nil } // _G.a.b.c = fn ok, err := luaPushMultiLevelTable(L, path) if !ok { return false, err } pushStringToLua(L, baseName) state.pushObjToLua(fn) C.lua_settable(vm.globalL, -3) return true, nil }
func (lua *Lua) PushGoValue(value reflect.Value) { switch t := value.Type(); t.Kind() { case reflect.Bool: if value.Bool() { C.lua_pushboolean(lua.State, C.int(1)) } else { C.lua_pushboolean(lua.State, C.int(0)) } case reflect.String: C.lua_pushstring(lua.State, C.CString(value.String())) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: C.lua_pushnumber(lua.State, C.lua_Number(C.longlong(value.Int()))) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: C.lua_pushnumber(lua.State, C.lua_Number(C.ulonglong(value.Uint()))) case reflect.Float32, reflect.Float64: C.lua_pushnumber(lua.State, C.lua_Number(C.double(value.Float()))) case reflect.Slice: length := value.Len() C.lua_createtable(lua.State, C.int(length), 0) for i := 0; i < length; i++ { C.lua_pushnumber(lua.State, C.lua_Number(i+1)) lua.PushGoValue(value.Index(i)) C.lua_settable(lua.State, -3) } case reflect.Interface: lua.PushGoValue(value.Elem()) case reflect.Ptr, reflect.UnsafePointer: C.lua_pushlightuserdata(lua.State, unsafe.Pointer(value.Pointer())) default: lua.Panic("wrong return value %v %v", value, t.Kind()) } }
func unpackMapToLua(state State, m *P.Map) { L := state.L n := len(m.Elems) C.lua_createtable(L, 0, 0) for i := 0; i < n; i++ { key := m.Elems[i].Key value := m.Elems[i].Value // key switch key.(type) { case int, int8, int32, int64, uint, uint8, uint32, uint64, float32, float64, string: UnpackObjectToLua(state, key) case []byte: bytes := key.([]byte) pushBytesToLua(L, bytes) default: continue } // value UnpackObjectToLua(state, value) C.lua_settable(L, -3) } }
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 }
func (tbl *Table) Set(key interface{}, value interface{}) (bool, error) { if tbl.Ref == 0 { return false, fmt.Errorf("cannot set a released lua table") } L := tbl.VM.globalL state := State{tbl.VM, L} bottom := C.lua_gettop(L) defer C.lua_settop(L, bottom) tbl.PushValue(state) vkey := reflect.ValueOf(key) ok := state.goToLuaValue(vkey) if !ok { return false, fmt.Errorf("invalid key type for lua type: %v", vkey.Kind()) } state.goToLuaValue(reflect.ValueOf(value)) C.lua_settable(L, C.int(-3)) return true, nil }
// lua_settable func (L *State) SetTable(index int) { C.lua_settable(L.s, C.int(index)) }
// Does the equivalent to t[k] = v, where t is the value at the given valid // index, v is the value at the top of the stack, and k is the value just // below the top. // // This function pops both the key and the value from the stack. As in Lua, // this function may trigger a metamethod for the "newindex" event. func (this *State) Settable(index int) { C.lua_settable(this.luastate, C.int(index)) }
// Does the equivalent to t[k] = v, where t is the value at the given valid // index, v is the value at the top of the stack, and k is the value just // below the top. // // This function pops both the key and the value from the stack. As in Lua, // this function may trigger a metamethod for the "newindex" event. func (s *State) Settable(index int) { C.lua_settable(s.l, C.int(index)) }
func (l *Lua) pushGoValue(v interface{}, name string) error { if v == nil { C.lua_pushnil(l.State) return nil } switch value := v.(type) { case bool: if value { C.lua_pushboolean(l.State, C.int(1)) } else { C.lua_pushboolean(l.State, C.int(0)) } case string: C.lua_pushstring(l.State, C.CString(value)) case int: C.lua_pushnumber(l.State, C.lua_Number(C.longlong(value))) case int8: C.lua_pushnumber(l.State, C.lua_Number(C.longlong(value))) case int16: C.lua_pushnumber(l.State, C.lua_Number(C.longlong(value))) case int32: C.lua_pushnumber(l.State, C.lua_Number(C.longlong(value))) case int64: C.lua_pushnumber(l.State, C.lua_Number(C.longlong(value))) case uint: C.lua_pushnumber(l.State, C.lua_Number(C.ulonglong(value))) case uint8: C.lua_pushnumber(l.State, C.lua_Number(C.ulonglong(value))) case uint16: C.lua_pushnumber(l.State, C.lua_Number(C.ulonglong(value))) case uint32: C.lua_pushnumber(l.State, C.lua_Number(C.ulonglong(value))) case uint64: C.lua_pushnumber(l.State, C.lua_Number(C.ulonglong(value))) case float32: C.lua_pushnumber(l.State, C.lua_Number(C.double(value))) case float64: C.lua_pushnumber(l.State, C.lua_Number(C.double(value))) case unsafe.Pointer: C.lua_pushlightuserdata(l.State, value) default: // not basic types, use reflect switch valueType := reflect.TypeOf(v); valueType.Kind() { case reflect.Func: // function if valueType.IsVariadic() { return fmt.Errorf("variadic function is not supported, %s", name) } function := &_Function{ name: name, lua: l, fun: v, funcType: valueType, funcValue: reflect.ValueOf(v), argc: valueType.NumIn(), } funcsLock.Lock() funcs = append(funcs, function) id := len(funcs) - 1 funcsLock.Unlock() C.push_go_func(l.State, C.int64_t(id)) case reflect.Slice: value := reflect.ValueOf(v) length := value.Len() C.lua_createtable(l.State, C.int(length), 0) for i := 0; i < length; i++ { C.lua_pushnumber(l.State, C.lua_Number(i+1)) err := l.pushGoValue(value.Index(i).Interface(), "") if err != nil { return err } C.lua_settable(l.State, -3) } case reflect.Ptr: C.lua_pushlightuserdata(l.State, unsafe.Pointer(reflect.ValueOf(v).Pointer())) default: // unknown type return fmt.Errorf("unsupported type %v", v) } } return nil }