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 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 (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 unpackArrayToLua(state State, a *P.Array) { L := state.L n := len(a.Elems) C.lua_createtable(L, C.int(n), 0) for i := 0; i < n; i++ { UnpackObjectToLua(state, a.Elems[i]) C.lua_rawseti(L, C.int(-2), C.int(i+1)) } }
// Peval evaluates a piece of lua code. no panic when error occur. func (l *Lua) Peval(code string, envs ...interface{}) (returns []interface{}, err error) { defer C.lua_settop(l.State, 0) C.push_errfunc(l.State) curTop := C.lua_gettop(l.State) // parse cCode := C.CString(code) defer C.free(unsafe.Pointer(cCode)) if ret := C.luaL_loadstring(l.State, cCode); ret != 0 { // load error return nil, fmt.Errorf("LOAD ERROR: %s", C.GoString(C.lua_tolstring(l.State, -1, nil))) } // env if len(envs) > 0 { if len(envs)%2 != 0 { return nil, fmt.Errorf("number of arguments not match") } C.lua_createtable(l.State, 0, 0) for i := 0; i < len(envs); i += 2 { name, ok := envs[i].(string) if !ok { return nil, fmt.Errorf("name must be string, not %v", envs[i]) } C.lua_pushstring(l.State, cstr(name)) err := l.pushGoValue(envs[i+1], name) if err != nil { return nil, err } C.lua_rawset(l.State, -3) } // set env C.set_eval_env(l.State) } // call l.err = nil if ret := C.lua_pcall(l.State, 0, C.LUA_MULTRET, -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 } if value != nil { returns[int(nReturn-1-i)] = value.Interface() } else { returns[int(nReturn-1-i)] = nil } } } 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 }
func luaKeys(state State) int { L := state.L vmap := mustBeMap(state, 2) if vmap == nil { C.lua_pushnil(L) pushStringToLua(L, "Keys() only apply to `map'") return 2 } vkeys := vmap.MapKeys() C.lua_createtable(L, C.int(len(vkeys)), 0) for i := 0; i < len(vkeys); i++ { if !state.goToLuaValue(vkeys[i]) { continue } C.lua_rawseti(L, C.int(-2), C.int(i+1)) } return 1 }
func (s *State) NewTable() { C.lua_createtable(s.L, 0, 0) }
// lua_newtable func (L *State) NewTable() { C.lua_createtable(L.s, 0, 0) }
// lua_createtable func (L *State) CreateTable(narr int, nrec int) { C.lua_createtable(L.s, C.int(narr), C.int(nrec)) }
// Creates a new empty table and pushes it onto the stack. The new table // has space pre-allocated for narr array elements and nrec non-array // elements. This pre-allocation is useful when you know exactly how many // elements the table will have. Otherwise you can use the function Newtable. func (this *State) Createtable(narr, nrec int) { if !this.Checkstack(1) { panic("STATE: unable to grow lua_state stack") } C.lua_createtable(this.luastate, C.int(narr), C.int(nrec)) }
// Creates a new empty table and pushes it onto the stack. The new table // has space pre-allocated for narr array elements and nrec non-array // elements. This pre-allocation is useful when you know exactly how many // elements the table will have. Otherwise you can use the function Newtable. func (s *State) Createtable(narr, nrec int) { C.lua_createtable(s.l, C.int(narr), C.int(nrec)) }
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 }
func Createtable(s *State, narr, nrec int) { C.lua_createtable((*C.lua_State)(s), C.int(narr), C.int(nrec)) }
func LuaL_newlibtable(L Lua_State, l unsafe.Pointer) { C.lua_createtable(Lua_CStatePtr(L), 0, LuaF_RegLen(l)) }