예제 #1
0
파일: pack.go 프로젝트: hxyxj/goinfi
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
}
예제 #2
0
파일: lobject.go 프로젝트: hxyxj/goinfi
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)
	}
}
예제 #3
0
파일: convert.go 프로젝트: hxyxj/goinfi
func (state State) goToLuaValue(value reflect.Value) bool {
	L := state.L
	gkind := value.Kind()
	switch gkind {
	case reflect.Bool:
		v := value.Bool()
		if v {
			C.lua_pushboolean(L, 1)
		} else {
			C.lua_pushboolean(L, 0)
		}
		return true
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		v := value.Int()
		C.lua_pushinteger(L, C.lua_Integer(v))
		return true
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		v := value.Uint()
		C.lua_pushinteger(L, C.lua_Integer(v))
		return true
	// case reflect.Uintptr:
	case reflect.Float32, reflect.Float64:
		v := value.Float()
		C.lua_pushnumber(L, C.lua_Number(v))
		return true

	// case reflect.Array:
	// case reflect.Complex64, reflect.Complex128:
	// case reflect.Chan
	// case reflect.Interface
	case reflect.Ptr:
		iv := value.Interface()
		if v, ok := iv.(ILuaRef); ok {
			v.PushValue(state)
			return true
		}
		state.pushObjToLua(value.Interface())
		return true
	case reflect.Func, reflect.Map, reflect.Slice:
		state.pushObjToLua(value.Interface())
		return true
	case reflect.String:
		v := value.String()
		pushStringToLua(L, v)
		return true
	case reflect.Struct:
		objPtr := reflect.New(value.Type())
		objPtr.Elem().Set(value)
		state.pushObjToLua(objPtr.Interface())
		return true
		//case reflect.UnsafePointer
	case reflect.Interface:
		return state.goToLuaValue(value.Elem())
	}
	C.lua_pushnil(L)
	return false
}
예제 #4
0
파일: gobject.go 프로젝트: hxyxj/goinfi
func sizeOfLuaTable(L *C.lua_State, ltable int) int {
	var size int = 0
	C.lua_pushnil(L)
	for {
		if 0 == C.lua_next(L, C.int(ltable)) {
			break
		}
		size++
		C.lua_settop(L, -2) // pop 1
	}
	return size
}
예제 #5
0
파일: lua.go 프로젝트: hxyxj/goinfi
//export GO_indexObject
func GO_indexObject(_L unsafe.Pointer, ref unsafe.Pointer, lkey C.int) (ret int) {
	L := (*C.lua_State)(_L)
	node := (*refGo)(ref)
	vm := node.vm
	state := State{vm, L}
	v := reflect.ValueOf(node.obj)
	t := v.Type()
	k := v.Kind()

	defer func() {
		if r := recover(); r != nil {
			pushStringToLua(L, fmt.Sprintf("%v", r))
			ret = -1
		}
	}()

	ltype := C.lua_type(L, lkey)
	switch k {
	case reflect.Slice:
		if ltype == C.LUA_TNUMBER {
			idx := int(C.lua_tointeger(L, lkey))
			value := v.Index(idx)
			state.goToLuaValue(value)
			return 1
		}
		panic(fmt.Sprintf("index of slice must be a number type, here got `%v'", luaTypeName(ltype)))
	case reflect.Map:
		keyType := t.Key()
		key, err := state.luaToGoValue(int(lkey), &keyType)
		if err != nil {
			panic(fmt.Sprintf("index type of map must be type `%v', %s", keyType.Kind(), err.Error()))
		}
		value := v.MapIndex(key)
		if !value.IsValid() {
			C.lua_pushnil(L)
			return 1
		}
		state.goToLuaValue(value)
		return 1
	case reflect.Ptr:
		if t.Elem().Kind() == reflect.Struct {
			ret, err := state.getStructField(v, lkey)
			if err != nil {
				panic(fmt.Sprintf("error when get field of struct, %s", err.Error()))
			}
			return ret
		}
	}

	panic(fmt.Sprintf("try to index a non-indexable go object, type `%v'", k))
	return -1
}
예제 #6
0
파일: pack.go 프로젝트: hxyxj/goinfi
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
}
예제 #7
0
파일: gobject.go 프로젝트: hxyxj/goinfi
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
}
예제 #8
0
파일: golang.go 프로젝트: hxyxj/goinfi
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
}
예제 #9
0
파일: lua.go 프로젝트: szll/golua
// lua_pushnil
func (L *State) PushNil() {
	C.lua_pushnil(L.s)
}
예제 #10
0
파일: state.go 프로젝트: halturin/luajit
// Pushes a nil value onto the stack.
func (s *State) Pushnil() {
	C.lua_pushnil(s.l)
}
예제 #11
0
파일: lgo.go 프로젝트: reusee/lgo
func (lua *Lua) toGoValue(i C.int, paramType reflect.Type) (ret reflect.Value) {
	luaType := C.lua_type(lua.State, i)
	paramKind := paramType.Kind()
	switch paramKind {
	case reflect.Bool:
		if luaType != C.LUA_TBOOLEAN {
			lua.Panic("not a boolean")
		}
		ret = reflect.ValueOf(C.lua_toboolean(lua.State, i) == C.int(1))
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if luaType != C.LUA_TNUMBER {
			lua.Panic("not an integer")
		}
		ret = reflect.New(paramType).Elem()
		ret.SetInt(int64(C.lua_tointegerx(lua.State, i, nil)))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if luaType != C.LUA_TNUMBER {
			lua.Panic("not an unsigned")
		}
		ret = reflect.New(paramType).Elem()
		ret.SetUint(uint64(C.lua_tointegerx(lua.State, i, nil)))
	case reflect.Float32, reflect.Float64:
		if luaType != C.LUA_TNUMBER {
			lua.Panic("not a float")
		}
		ret = reflect.New(paramType).Elem()
		ret.SetFloat(float64(C.lua_tonumberx(lua.State, i, nil)))
	case reflect.Interface:
		switch luaType {
		case C.LUA_TNUMBER:
			ret = reflect.New(floatType).Elem()
			ret.SetFloat(float64(C.lua_tonumberx(lua.State, i, nil)))
		case C.LUA_TSTRING:
			ret = reflect.New(stringType).Elem()
			ret.SetString(C.GoString(C.lua_tolstring(lua.State, i, nil)))
		case C.LUA_TLIGHTUSERDATA:
			ret = reflect.ValueOf(C.lua_topointer(lua.State, i))
		case C.LUA_TBOOLEAN:
			ret = reflect.New(boolType).Elem()
			ret.SetBool(C.lua_toboolean(lua.State, i) == C.int(1))
		//TODO nil
		//TODO table
		default:
			lua.Panic("wrong interface argument: %v", paramKind)
		}
	case reflect.String:
		if luaType != C.LUA_TSTRING {
			lua.Panic("not a string")
		}
		ret = reflect.New(paramType).Elem()
		ret.SetString(C.GoString(C.lua_tolstring(lua.State, i, nil)))
	case reflect.Slice:
		switch luaType {
		case C.LUA_TSTRING:
			ret = reflect.New(paramType).Elem()
			cstr := C.lua_tolstring(lua.State, i, nil)
			ret.SetBytes(C.GoBytes(unsafe.Pointer(cstr), C.int(C.strlen(cstr))))
		case C.LUA_TTABLE:
			ret = reflect.MakeSlice(paramType, 0, 0)
			C.lua_pushnil(lua.State)
			elemType := paramType.Elem()
			for C.lua_next(lua.State, i) != 0 {
				ret = reflect.Append(ret, lua.toGoValue(-1, elemType))
				C.lua_settop(lua.State, -2)
			}
		default:
			lua.Panic("wrong slice argument")
		}
	case reflect.Ptr:
		if luaType != C.LUA_TLIGHTUSERDATA {
			lua.Panic("not a pointer")
		}
		pointer := C.lua_topointer(lua.State, i)
		ret = reflect.NewAt(paramType, unsafe.Pointer(&pointer)).Elem()
	case reflect.Map:
		if luaType != C.LUA_TTABLE {
			lua.Panic("not a map")
		}
		ret = reflect.MakeMap(paramType)
		C.lua_pushnil(lua.State)
		keyType := paramType.Key()
		elemType := paramType.Elem()
		for C.lua_next(lua.State, i) != 0 {
			ret.SetMapIndex(
				lua.toGoValue(-2, keyType),
				lua.toGoValue(-1, elemType))
			C.lua_settop(lua.State, -2)
		}
	case reflect.UnsafePointer:
		ret = reflect.ValueOf(C.lua_topointer(lua.State, i))
	//TODO complex64/128
	//TODO array
	//TODO chan
	//TODO func
	//TODO struct
	default:
		lua.Panic("unknown argument type %v", paramType)
	}
	return
}
예제 #12
0
파일: lua.go 프로젝트: reusee/lua
func (l *Lua) toGoValue(i C.int, paramType reflect.Type) (ret *reflect.Value, err error) {
	luaType := C.lua_type(l.State, i)
	paramKind := paramType.Kind()
	switch paramKind {
	case reflect.Bool:
		if luaType != C.LUA_TBOOLEAN {
			err = fmt.Errorf("not a boolean")
			return
		}
		v := reflect.ValueOf(C.lua_toboolean(l.State, i) == C.int(1))
		ret = &v
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if luaType != C.LUA_TNUMBER {
			err = fmt.Errorf("not an integer")
			return
		}
		v := reflect.New(paramType).Elem()
		v.SetInt(int64(C.lua_tointeger(l.State, i)))
		ret = &v
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if luaType != C.LUA_TNUMBER {
			err = fmt.Errorf("not a unsigned")
			return
		}
		v := reflect.New(paramType).Elem()
		v.SetUint(uint64(C.lua_tointeger(l.State, i)))
		ret = &v
	case reflect.Float32, reflect.Float64:
		if luaType != C.LUA_TNUMBER {
			err = fmt.Errorf("not a float")
			return
		}
		v := reflect.New(paramType).Elem()
		v.SetFloat(float64(C.lua_tonumber(l.State, i)))
		ret = &v
	case reflect.Interface:
		switch paramType {
		case interfaceType:
			switch luaType {
			case C.LUA_TNUMBER:
				v := reflect.New(floatType).Elem() // always return float64 for interface{}
				v.SetFloat(float64(C.lua_tonumber(l.State, i)))
				ret = &v
			case C.LUA_TSTRING:
				v := reflect.New(stringType).Elem()
				v.SetString(C.GoString(C.lua_tolstring(l.State, i, nil)))
				ret = &v
			case C.LUA_TLIGHTUSERDATA, C.LUA_TUSERDATA:
				v := reflect.ValueOf(C.lua_touserdata(l.State, i))
				ret = &v
			case C.LUA_TBOOLEAN:
				v := reflect.New(boolType).Elem()
				v.SetBool(C.lua_toboolean(l.State, i) == C.int(1))
				ret = &v
			case C.LUA_TNIL:
				ret = nil
			default:
				err = fmt.Errorf("unsupported type %s for interface{}", luaTypeName(luaType))
				return
			}
		default:
			err = fmt.Errorf("only interface{} is supported, no %v", paramType)
			return
		}
	case reflect.String:
		if luaType != C.LUA_TSTRING {
			err = fmt.Errorf("not a string")
			return
		}
		v := reflect.New(paramType).Elem()
		v.SetString(C.GoString(C.lua_tolstring(l.State, i, nil)))
		ret = &v
	case reflect.Slice:
		switch luaType {
		case C.LUA_TSTRING:
			v := reflect.New(paramType).Elem()
			cstr := C.lua_tolstring(l.State, i, nil)
			v.SetBytes(C.GoBytes(unsafe.Pointer(cstr), C.int(C.strlen(cstr))))
			ret = &v
		case C.LUA_TTABLE:
			v := reflect.MakeSlice(paramType, 0, 0)
			C.lua_pushnil(l.State)
			elemType := paramType.Elem()
			for C.lua_next(l.State, i) != 0 {
				elemValue, e := l.toGoValue(-1, elemType)
				if e != nil {
					err = e
					return
				}
				// there is no nil value in lua table so elemValue will never be nil
				v = reflect.Append(v, *elemValue)
				C.lua_settop(l.State, -2)
				ret = &v
			}
		default:
			err = fmt.Errorf("wrong slice argument")
			return
		}
	case reflect.Ptr:
		if luaType != C.LUA_TLIGHTUSERDATA {
			err = fmt.Errorf("not a pointer")
			return
		}
		p := C.lua_topointer(l.State, i)
		v := reflect.NewAt(paramType, unsafe.Pointer(&p)).Elem()
		ret = &v
	case reflect.Map:
		if luaType != C.LUA_TTABLE {
			err = fmt.Errorf("not a map")
			return
		}
		v := reflect.MakeMap(paramType)
		C.lua_pushnil(l.State)
		keyType := paramType.Key()
		elemType := paramType.Elem()
		for C.lua_next(l.State, i) != 0 {
			keyValue, e := l.toGoValue(-2, keyType)
			if e != nil {
				err = e
				return
			}
			// table has no nil key so keyValue will not be nil
			elemValue, e := l.toGoValue(-1, elemType)
			if e != nil {
				err = e
				return
			}
			// table has no nil value so elemValue will not be nil
			v.SetMapIndex(*keyValue, *elemValue)
			C.lua_settop(l.State, -2)
		}
		ret = &v
	case reflect.UnsafePointer:
		v := reflect.ValueOf(C.lua_topointer(l.State, i))
		ret = &v
	default:
		err = fmt.Errorf("unsupported toGoValue type %v", paramType)
		return
	}
	return
}
예제 #13
0
파일: lua.go 프로젝트: reusee/lua
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
}