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) }
// Formats a string and pushes it into the stack. Provides all formatting // verbs found in package fmt. Returns a pointer to the resultant // formatted string. func (s *State) Pushfstring(format string, v ...interface{}) *string { str := fmt.Sprintf(format, v) cs := C.CString(str) defer C.free(unsafe.Pointer(cs)) C.lua_pushstring(s.l, cs) return &str }
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 main() { L := C.luaL_newstate() defer C.lua_close(L) C.luaL_openlibs(L) /* Load Lua libraries */ C.luaopen_cmsgpack(L) sumS := C.CString(sum) defer C.free(unsafe.Pointer(sumS)) C.luaL_loadstring(L, sumS) msg, _ := msgpack.Marshal([]int{1, 2, 3, 4, 5, 6}) C.lua_pushstring(L, cptr(msg)) dstr := C.CString("mpdata") defer C.free(unsafe.Pointer(dstr)) C.luaSetglobal(L, dstr) C.luaExecute(L) sum := C.lua_tonumber(L, -1) fmt.Println(sum) // Output: 21 }
// 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 }
// 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 }
// Pushes the string str onto the stack. func (this *State) Pushstring(str string) { cs := C.CString(str) defer C.free(unsafe.Pointer(cs)) C.lua_pushstring(this.luastate, cs) }
func (L *State) PushString(str string) { C.lua_pushstring(L.s, C.CString(str)) }
func (L *State) PushString(str string) { Cstr := C.CString(str) defer C.free(unsafe.Pointer(Cstr)) C.lua_pushstring(L.s, Cstr) }
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 (L *State) pushString(str string) { cs := C.CString(str) defer C.free(unsafe.Pointer(cs)) C.lua_pushstring(L.s, cs) }