Exemple #1
0
func (tbl *Table) Foreach(fn func(key interface{}, value interface{}) bool) {
	if tbl.Ref == 0 {
		return
	}

	L := tbl.VM.globalL
	state := State{tbl.VM, L}
	bottom := C.lua_gettop(L)
	defer C.lua_settop(L, bottom)
	tbl.PushValue(state)

	ltable := C.lua_gettop(L)
	C.lua_pushnil(L)
	for {
		if 0 == C.lua_next(L, ltable) {
			return
		}

		vkey, err := state.luaToGoValue(-2, nil)
		if err != nil {
			return
		}
		vvalue, err := state.luaToGoValue(-1, nil)
		if err != nil {
			return
		}

		cont := fn(vkey.Interface(), vvalue.Interface())
		if !cont {
			return
		}

		C.lua_settop(L, -2)
	}
}
Exemple #2
0
// 调用lua中的函数,但是只能返回bool, float, string,以及其他go特殊类型,int型被转换为float返回。
func (L *State) Call(fname string, args ...interface{}) (out []interface{}, ok bool) {
	fn := C.CString(fname)
	defer C.free(unsafe.Pointer(fn))

	top := int(C.lua_gettop(L.s))

	if C.int(1) != C.FindFuncs(L.s, fn) {
		ok = false
		out = append(out, errors.New(fmt.Sprintf("not find the function(%s).\n", fname)))
		return
	}

	num := len(args)
	for _, arg := range args {
		argt := rf.TypeOf(arg)
		argv := rf.ValueOf(arg)
		L.pushValueByType(argt.Kind(), &argv)
	}

	C.lua_call(L.s, C.int(num), C.LUA_MULTRET)

	for i := top; i < int(C.lua_gettop(L.s)); i++ {
		ret := L.getValueByLuaType(i)
		if ret.IsValid() {
			out = append(out, ret.Interface())
		} else {
			out = append(out, nil)
		}
	}
	C.lua_settop(L.s, C.int(top))
	ok = true
	return
}
Exemple #3
0
// 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
}
Exemple #4
0
//export Invoke
func Invoke(funcId int64) int {
	function, ok := functionRegister.Get(funcId)
	if !ok { //NOCOVER
		panic(fmt.Sprintf("invalid function id %d\n", funcId))
	}
	// check argument count
	argc := C.lua_gettop(function.lua.State)
	if int(argc) != function.argc {
		function.lua.Panic("arguments not match: %v", function.fun)
	}
	// arguments
	var args []reflect.Value
	for i := C.int(1); i <= argc; i++ {
		args = append(args, function.lua.toGoValue(i, function.funcType.In(int(i-1))))
	}
	// call and returns
	returnValues := function.funcValue.Call(args)
	if len(returnValues) != function.funcType.NumOut() { //NOCOVER
		function.lua.Panic("return values not match: %v", function.fun)
	}
	for _, v := range returnValues {
		function.lua.PushGoValue(v)
	}
	return len(returnValues)
}
Exemple #5
0
func (tbl *Table) GetWithError(key interface{}) (interface{}, error) {
	if tbl.Ref == 0 {
		return nil, fmt.Errorf("cannot get 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 nil, fmt.Errorf("invalid key type for lua type: %v", vkey.Kind())
	}
	C.lua_gettable(L, C.int(-2))
	vvalue, err := state.luaToGoValue(-1, nil)
	if err != nil {
		return nil, err
	}

	if vvalue.IsValid() {
		return vvalue.Interface(), nil
	}
	return nil, nil
}
Exemple #6
0
// 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
}
Exemple #7
0
func callLuaFuncUtil(state State, inv []reflect.Value, nout int) ([]interface{}, error) {
	L := state.L
	bottom := int(C.lua_gettop(L))

	var result []interface{}
	var nluaout C.int
	var nin C.int
	if nout >= 0 {
		nluaout = C.int(nout)
		result = make([]interface{}, 0, nout)
	} else {
		nluaout = C.LUA_MULTRET
		result = make([]interface{}, 0, 1)
	}
	if inv != nil {
		for _, iarg := range inv {
			state.goToLuaValue(iarg)
		}
		nin = C.int(len(inv))
	} else {
		nin = 0
	}
	ret := int(C.lua_pcall(L, nin, nluaout, 0))
	if ret != 0 {
		err := stringFromLua(L, -1)
		C.lua_settop(L, -2)
		return result, errors.New(err)
	}
	top := int(C.lua_gettop(L))
	for i := bottom; i <= top; i++ {
		value, _ := state.luaToGoValue(i, nil)
		if value.IsValid() {
			result = append(result, value.Interface())
		} else {
			result = append(result, nil)
		}
	}
	rnout := C.int(top + 1 - bottom)
	C.lua_settop(L, -rnout-1)
	return result, nil
}
Exemple #8
0
func packLuaTable(out io.Writer, state State, object int, depth int) (n int, err error) {
	depth++
	L := state.L

	if depth > MAX_PACK_DEPTH {
		return 0, fmt.Errorf("pack too depth, depth=%v", depth)
	}

	n = 0
	err = nil
	var mapSize int = 0
	C.lua_pushnil(L)
	for {
		if 0 == C.lua_next(L, C.int(object)) {
			break
		}
		mapSize++
		C.lua_settop(L, -2) // pop 1
	}

	var ni int
	ni, err = P.PackMapHead(out, uint32(mapSize))
	n += ni
	if err != nil {
		return
	}

	C.lua_pushnil(L)
	for {
		if 0 == C.lua_next(L, C.int(object)) {
			break
		}

		top := int(C.lua_gettop(L))
		// key
		ni, err = packLuaObject(out, state, top-1, depth)
		n += ni
		if err != nil {
			C.lua_settop(L, -3) // pop 2
			return
		}
		// value
		ni, err = packLuaObject(out, state, top, depth)
		n += ni
		if err != nil {
			C.lua_settop(L, -3) // pop 2
			return
		}
		C.lua_settop(L, -2) // removes value, keeps key for next iteration
	}

	return
}
Exemple #9
0
func (tbl *Table) GetnWithError() (int, error) {
	if tbl.Ref == 0 {
		return 0, fmt.Errorf("cannot get lenght a released lua table")
	}
	L := tbl.VM.globalL
	state := State{tbl.VM, L}
	bottom := int(C.lua_gettop(L))
	defer C.lua_settop(L, C.int(bottom))

	tbl.PushValue(state)

	n := int(C.lua_objlen(L, C.int(-1)))
	return n, nil
}
Exemple #10
0
func PackLuaObjects(out io.Writer, state State, from int, to int) (ok bool, err error) {
	L := state.L
	top := C.lua_gettop(L)
	ok = true
	err = nil
	for object := from; object <= to; object++ {
		_, err = PackLuaObject(out, state, object)
		if err != nil {
			ok = false
			break
		}
	}
	C.lua_settop(L, top)
	return ok, err
}
Exemple #11
0
func luaPackToString(state State) int {
	// arg 1 is func udata itself
	var out bytes.Buffer
	L := state.L
	from := 2
	to := int(C.lua_gettop(state.L))
	ok, err := PackLuaObjects(&out, state, from, to)
	if !ok {
		C.lua_pushnil(L)
		pushStringToLua(L, fmt.Sprintf("%v", err))
		return 2
	}
	pushBytesToLua(L, out.Bytes())
	return 1
}
Exemple #12
0
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
}
Exemple #13
0
func luaPushMultiLevelTable(L *C.lua_State, path []string) (bool, error) {
	ok, _ := luaGetSubTable(L, C.LUA_GLOBALSINDEX, path[0])
	if !ok {
		return false, fmt.Errorf("field `%v` exist, and it is not a table", path[0])
	}

	for i := 1; i < len(path); i++ {
		table := C.lua_gettop(L)
		ok, _ := luaGetSubTable(L, table, path[i])
		if !ok {
			return false, fmt.Errorf("field `%v` exist, and it is not a table", strings.Join(path[:i+1], "."))
		}
	}

	return true, nil
}
Exemple #14
0
//export invokeGoFunc
func invokeGoFunc(state *C.lua_State) int {
	id := C.lua_tointeger(state, C.LUA_GLOBALSINDEX-1)
	funcsLock.RLock()
	function := funcs[id]
	funcsLock.RUnlock()
	// fast paths
	switch f := function.fun.(type) {
	case func():
		f()
		return 0
	}
	// check args
	argc := C.lua_gettop(state)
	if int(argc) != function.argc {
		// Lua.Eval will check err
		function.lua.err = fmt.Errorf("CALL ERROR: number of arguments not match: %s\n%s",
			function.name, function.lua.getStackTraceback())
		return 0
	}
	// prepare args
	var args []reflect.Value
	for i := C.int(1); i <= argc; i++ {
		goValue, err := function.lua.toGoValue(i, function.funcType.In(int(i-1)))
		if err != nil {
			function.lua.err = fmt.Errorf("CALL ERROR: toGoValue error: %v\n%s",
				err, function.lua.getStackTraceback())
			return 0
		}
		if goValue != nil {
			args = append(args, *goValue)
		} else {
			args = append(args, reflect.Zero(function.funcType.In(int(i-1))))
		}
	}
	// call and returns
	returnValues := function.funcValue.Call(args)
	for _, v := range returnValues {
		function.lua.pushGoValue(v.Interface(), "")
	}
	return len(returnValues)
}
Exemple #15
0
func (vm *VM) EvalStringWithError(str string, arg ...interface{}) ([]interface{}, error) {
	L := vm.globalL
	state := State{vm, L}
	s, n := stringToC(str)
	bottom := C.lua_gettop(L)
	defer C.lua_settop(L, bottom)

	ret := int(C.luaL_loadbuffer(L, s, n, nil))
	if ret != 0 {
		err := stringFromLua(L, -1)
		return make([]interface{}, 0), errors.New(err)
	}

	nout := -1
	if len(arg) > 0 {
		if x, ok := arg[0].(int); ok {
			nout = x
		}
	}
	return callLuaFuncUtil(state, nil, nout)
}
Exemple #16
0
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
}
Exemple #17
0
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)))
	}
}
Exemple #18
0
func (self *Lua) RunString(code string) {
	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)
		}
	}()
	cCode := cstr(code)
	C.setup_message_handler(self.State)
	if ret := C.luaL_loadstring(self.State, cCode); ret != C.int(0) {
		self.Panic("%s", C.GoString(C.lua_tolstring(self.State, -1, nil)))
	}
	ret := C.lua_pcallk(self.State, 0, 0, C.lua_gettop(self.State)-C.int(1), 0, nil)
	if ret != C.int(0) {
		self.Panic("%s", C.GoString(C.lua_tolstring(self.State, -1, nil)))
	}
	C.lua_settop(self.State, 0)
}
Exemple #19
0
func (vm *VM) EvalBufferWithError(reader io.Reader, arg ...interface{}) ([]interface{}, error) {
	L := vm.globalL
	state := State{vm, L}
	context := loadBufferContext{
		reader: reader,
		buf:    make([]byte, READ_BUFFER_SIZE),
	}
	bottom := C.lua_gettop(L)
	defer C.lua_settop(L, bottom)

	ret := int(C.clua_loadProxy(L, unsafe.Pointer(&context)))
	if ret != 0 {
		err := stringFromLua(L, -1)
		return make([]interface{}, 0), errors.New(err)
	}
	nout := -1
	if len(arg) > 0 {
		if x, ok := arg[0].(int); ok {
			nout = x
		}
	}
	return callLuaFuncUtil(state, nil, nout)
}
Exemple #20
0
func (L *State) getFuncIn(ft rf.Type) []rf.Value {
	var in []rf.Value
	var i int
	for i = 0; i < ft.NumIn()-1; i++ {
		in = append(in, *L.getValueByType(ft.In(i).Kind(), i))
	}

	switch {
	case ft.IsVariadic():
		ek := ft.In(i).Elem().Kind()
		for ; i < int(C.lua_gettop(L.s)); i++ {
			switch ek {
			case rf.Interface:
				in = append(in, *L.getValueByLuaType(i))
			default:
				in = append(in, *L.getValueByType(ek, i))
			}
		}
	case i < ft.NumIn():
		in = append(in, *L.getValueByType(ft.In(i).Kind(), i))
	}
	return in
}
Exemple #21
0
// lua_gettop
func (L *State) GetTop() int { return int(C.lua_gettop(L.s)) }
Exemple #22
0
// Returns the index of the top element in the stack. Because indices start
// at 1, this result is equal to the number of elements in the stack (and
// so 0 means an empty stack).
func (this *State) Gettop() int {
	return int(C.lua_gettop(this.luastate))
}
Exemple #23
0
// Returns the index of the top element in the stack. Because indices start
// at 1, this result is equal to the number of elements in the stack (and
// so 0 means an empty stack).
func (s *State) Gettop() int {
	return int(C.lua_gettop(s.l))
}
Exemple #24
0
//export GO_callObject
func GO_callObject(_L unsafe.Pointer, ref unsafe.Pointer) int {
	L := (*C.lua_State)(_L)
	node := (*refGo)(ref)
	obj := node.obj
	vm := node.vm
	state := State{vm, L}
	v := reflect.ValueOf(obj)
	k := v.Kind()

	if k != reflect.Func {
		pushStringToLua(L, fmt.Sprintf("try to call a non-function go object, type `%v'", k))
		return -1
	}

	t := v.Type()
	ningo := t.NumIn()
	if ningo == 1 {
		if t.In(0) == reflect.TypeOf(state) {
			return state.safeRawCall(v)
		}
	}

	ltop := int(C.lua_gettop(L))
	in := make([]reflect.Value, ningo)
	ilua := 2
	if t.IsVariadic() {
		for i := 0; i < ningo-1; i++ {
			tin := t.In(i)
			value, err := state.luaToGoValue(ilua, &tin)
			if err != nil {
				pushCallArgError(L, ilua, err)
				return -1
			}
			in[i] = value
			ilua++
		}
		nvarg := ltop - (ilua - 1)
		varg := reflect.MakeSlice(t.In(ningo-1), nvarg, nvarg)
		vargType := t.In(ningo - 1).Elem()
		for i := 0; i < nvarg; i++ {
			value, err := state.luaToGoValue(ilua, &vargType)
			if err != nil {
				pushCallArgError(L, ilua, err)
				return -1
			}
			if value.IsValid() {
				varg.Index(i).Set(value)
			}
			ilua++
		}
		in[ningo-1] = varg
	} else {
		for i := 0; i < ningo; i++ {
			tin := t.In(i)
			value, err := state.luaToGoValue(ilua, &tin)
			if err != nil {
				pushCallArgError(L, ilua, err)
				return -1
			}
			in[i] = value
			ilua++
		}
	}

	ok, out, err := safeCall(v, in)
	if !ok {
		pushStringToLua(L, "call go func error: "+err.Error())
		return -1
	}

	for _, value := range out {
		state.goToLuaValue(value)
	}

	return len(out)
}