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 (self *Lua) CallFunction(name string, args ...interface{}) { defer func() { if r := recover(); r != nil { if self.PrintTraceback { //NOCOVER print("============ start lua traceback ============\n") self.RunString(`print(debug.traceback())`) print("============ end lua traceback ==============\n") } panic(r) } }() cName := cstr(name) C.setup_message_handler(self.State) C.lua_getglobal(self.State, cName) for _, arg := range args { self.PushGoValue(reflect.ValueOf(arg)) } ret := C.lua_pcallk(self.State, C.int(len(args)), 0, C.lua_gettop(self.State)-C.int(len(args)+2), 0, nil) if ret != C.int(0) { self.Panic("%s", C.GoString(C.lua_tolstring(self.State, -1, nil))) } }
// Pushes onto the stack the value of the global name. func (this *State) Getglobal(name string) { ck := C.CString(name) defer C.free(unsafe.Pointer(ck)) C.lua_getglobal(this.luastate, ck) }