示例#1
1
文件: luar.go 项目: imvu/Tetra
// Copy matching Lua table entries to a struct, given the struct type
// and the index on the Lua stack.
func CopyTableToStruct(L *lua.State, t reflect.Type, idx int) interface{} {
	was_ptr := t.Kind() == reflect.Ptr
	if was_ptr {
		t = t.Elem()
	}
	s := reflect.New(t) // T -> *T
	ref := s.Elem()
	L.PushNil()
	if idx < 0 {
		idx--
	}
	for L.Next(idx) != 0 {
		key := L.ToString(-2)
		f := ref.FieldByName(strings.Title(key))
		if f.IsValid() {
			val := luaToGoValue(L, f.Type(), -1)
			f.Set(val)
		}
		L.Pop(1)
	}
	if was_ptr {
		return s.Interface()
	}
	return s.Elem().Interface()
}
示例#2
0
文件: luar.go 项目: stevedonovan/luar
// Also for arrays.
func copySliceToTable(L *lua.State, vslice reflect.Value, visited visitor) int {
	ref := vslice
	for vslice.Kind() == reflect.Ptr {
		// For arrays.
		vslice = vslice.Elem()
	}

	if vslice.IsValid() && (vslice.Kind() == reflect.Slice || vslice.Kind() == reflect.Array) {
		n := vslice.Len()
		L.CreateTable(n, 0)
		if vslice.Kind() == reflect.Slice {
			visited.mark(vslice)
		} else if ref.Kind() == reflect.Ptr {
			visited.mark(ref)
		}

		for i := 0; i < n; i++ {
			L.PushInteger(int64(i + 1))
			v := vslice.Index(i)
			if isNil(v) {
				v = nullv
			}
			goToLua(L, nil, v, true, visited)
			L.SetTable(-3)
		}
		return 1
	}
	L.PushNil()
	L.PushString("not a slice/array")
	return 2
}
示例#3
0
文件: lua.go 项目: 12foo/apiplexy
func popMap(L *lua.State) map[string]interface{} {
	m := make(map[string]interface{})
	L.PushNil()
	for L.Next(-2) != 0 {
		if L.IsString(-2) {
			var v interface{}
			if L.IsBoolean(-1) {
				v = L.ToBoolean(-1)
			} else if L.IsNumber(-1) {
				var t float64
				t = L.ToNumber(-1)
				if t == float64(int64(t)) {
					v = int(t)
				} else {
					v = t
				}
			} else if L.IsString(-1) {
				v = L.ToString(-1)
			} else if L.IsNil(-1) {
				v = nil
			} else if L.IsTable(-1) {
				v = popMap(L)
			}
			m[L.ToString(-2)] = v
		}
		L.Pop(1)
	}
	return m
}
示例#4
0
文件: lua.go 项目: 12foo/apiplexy
func pushMap(L *lua.State, m map[string]interface{}, lower bool) {
	L.CreateTable(0, len(m))
	for k, v := range m {
		if lower {
			L.PushString(strings.ToLower(k))
		} else {
			L.PushString(k)
		}
		switch t := v.(type) {
		case string:
			L.PushString(t)
		case int64:
			L.PushInteger(t)
		case int:
			L.PushInteger(int64(t))
		case float64:
			L.PushNumber(t)
		case bool:
			L.PushBoolean(t)
		case map[string]interface{}:
			pushMap(L, t, false)
		default:
			L.PushNil()
		}
		L.SetTable(-3)
	}
}
示例#5
0
文件: luar.go 项目: stevedonovan/luar
func copyStructToTable(L *lua.State, vstruct reflect.Value, visited visitor) int {
	// If 'vstruct' is a pointer to struct, use the pointer to mark as visited.
	ref := vstruct
	for vstruct.Kind() == reflect.Ptr {
		vstruct = vstruct.Elem()
	}

	if vstruct.IsValid() && vstruct.Type().Kind() == reflect.Struct {
		n := vstruct.NumField()
		L.CreateTable(n, 0)
		if ref.Kind() == reflect.Ptr {
			visited.mark(ref)
		}

		for i := 0; i < n; i++ {
			st := vstruct.Type()
			field := st.Field(i)
			key := field.Name
			tag := field.Tag.Get("lua")
			if tag != "" {
				key = tag
			}
			goToLua(L, nil, reflect.ValueOf(key), true, visited)
			v := vstruct.Field(i)
			goToLua(L, nil, v, true, visited)
			L.SetTable(-3)
		}
		return 1
	}
	L.PushNil()
	L.PushString("not a struct")
	return 2
}
示例#6
0
文件: luar.go 项目: stevedonovan/luar
func copyTableToMap(L *lua.State, t reflect.Type, idx int, visited map[uintptr]interface{}) interface{} {
	if t == nil {
		t = tmap
	}
	te, tk := t.Elem(), t.Key()
	m := reflect.MakeMap(t)

	// See copyTableToSlice.
	ptr := L.ToPointer(idx)
	if !luaIsEmpty(L, idx) {
		visited[ptr] = m.Interface()
	}

	L.PushNil()
	if idx < 0 {
		idx--
	}
	for L.Next(idx) != 0 {
		// key at -2, value at -1
		key := reflect.ValueOf(luaToGo(L, tk, -2, visited))
		val := reflect.ValueOf(luaToGo(L, te, -1, visited))
		if val.Interface() == nullv.Interface() {
			val = reflect.Zero(te)
		}
		m.SetMapIndex(key, val)
		L.Pop(1)
	}
	return m.Interface()
}
示例#7
0
func outputNumbersToStrings(L *lua.State) {
	L.GetGlobal("output")

	if !L.IsTable(-1) {
		L.NewTable()
		L.SetGlobal("output")
	}

	L.GetField(-1, "tags")
	if L.IsTable(-1) {
		// First key.
		L.PushNil()
		for L.Next(-2) != 0 {
			// Use 'key' at index -2 and 'value' at index -1.
			if L.IsString(-2) && L.IsString(-1) {
				// Convert numbers to strings.
				L.ToString(-1)
				L.SetField(-3, L.ToString(-2))
			} else {
				// Remove 'value' and keep 'key' for next iteration.
				L.Pop(1)
			}
		}
	}
	L.Pop(1)

	L.Pop(1)
}
示例#8
0
文件: luar.go 项目: imvu/Tetra
func proxyType(L *lua.State) int {
	v := unwrapProxy(L, 1)
	if v != nil {
		GoToLua(L, nil, valueOf(reflect.TypeOf(v)), false)
	} else {
		L.PushNil()
	}
	return 1
}
示例#9
0
func pairsAux(L *lua.State) int {
	L.CheckType(1, lua.LUA_TTABLE)
	L.SetTop(2) // Create a 2nd argument if there isn't one.
	if L.Next(1) != 0 {
		return 2
	}
	L.PushNil()
	return 1
}
示例#10
0
// Unproxify converts a proxy to an unproxified Lua value.
//
// Argument: proxy
//
// Returns: value (Lua value)
func Unproxify(L *lua.State) int {
	if !isValueProxy(L, 1) {
		L.PushNil()
		return 1
	}
	v, _ := valueOfProxy(L, 1)
	GoToLua(L, nil, v, true)
	return 1
}
示例#11
0
// ProxyMethod pushes the proxy method on the stack.
//
// Argument: proxy
//
// Returns: method (function)
func ProxyMethod(L *lua.State) int {
	if !isValueProxy(L, 1) {
		L.PushNil()
		return 1
	}
	v, _ := valueOfProxy(L, 1)
	name := L.ToString(2)
	pushGoMethod(L, name, v)
	return 1
}
示例#12
0
文件: luar.go 项目: stevedonovan/luar
func luaIsEmpty(L *lua.State, idx int) bool {
	L.PushNil()
	if idx < 0 {
		idx--
	}
	if L.Next(idx) != 0 {
		L.Pop(2)
		return false
	}
	return true
}
示例#13
0
// ProxyRaw unproxifies a value.
//
// WARNING: Deprecated, use luar.unproxify instead.
func ProxyRaw(L *lua.State) int {
	v := mustUnwrapProxy(L, 1)
	val := reflect.ValueOf(v)
	tp := predeclaredScalarType(val.Type())
	if tp != nil {
		val = val.Convert(tp)
		GoToLua(L, nil, val, false)
	} else {
		L.PushNil()
	}
	return 1
}
示例#14
0
文件: luar.go 项目: stevedonovan/luar
func copyTableToStruct(L *lua.State, t reflect.Type, idx int, visited map[uintptr]interface{}) interface{} {
	if t == nil {
		RaiseError(L, "type argument must be non-nill")
	}
	wasPtr := t.Kind() == reflect.Ptr
	if wasPtr {
		t = t.Elem()
	}
	s := reflect.New(t) // T -> *T
	ref := s.Elem()

	// See copyTableToSlice.
	ptr := L.ToPointer(idx)
	if !luaIsEmpty(L, idx) {
		if wasPtr {
			visited[ptr] = s.Interface()
		} else {
			visited[ptr] = s.Elem().Interface()
		}
	}

	// Associate Lua keys with Go fields: tags have priority over matching field
	// name.
	fields := map[string]string{}
	st := ref.Type()
	for i := 0; i < ref.NumField(); i++ {
		field := st.Field(i)
		tag := field.Tag.Get("lua")
		if tag != "" {
			fields[tag] = field.Name
			continue
		}
		fields[field.Name] = field.Name
	}

	L.PushNil()
	if idx < 0 {
		idx--
	}
	for L.Next(idx) != 0 {
		key := L.ToString(-2)
		f := ref.FieldByName(fields[key])
		if f.CanSet() && f.IsValid() {
			val := reflect.ValueOf(luaToGo(L, f.Type(), -1, visited))
			f.Set(val)
		}
		L.Pop(1)
	}
	if wasPtr {
		return s.Interface()
	}
	return s.Elem().Interface()
}
示例#15
0
// ProxyType pushes the proxy type on the stack.
//
// Argument: proxy
//
// Returns: type (string)
func ProxyType(L *lua.State) int {
	if !isValueProxy(L, 1) {
		L.PushNil()
		return 1
	}
	v, _ := valueOfProxy(L, 1)
	if v.Interface() == nil {
		L.PushNil()
		return 1
	}
	GoToLua(L, nil, reflect.ValueOf(v.Type()), false)
	return 1
}
示例#16
0
文件: luar.go 项目: imvu/Tetra
func proxyRaw(L *lua.State) int {
	v := unwrapProxyOrComplain(L, 1)
	t := reflect.TypeOf(v)
	tp := isPrimitiveDerived(t, t.Kind())
	if tp != nil {
		val := valueOf(v)
		val = val.Convert(tp)
		GoToLua(L, nil, val, false)
	} else {
		L.PushNil()
	}
	return 1
}
示例#17
0
// ProxyPairs implements Lua 5.2 'pairs' functions.
// It respects the __pairs metamethod.
//
// It is only useful for compatibility with Lua 5.1.
func ProxyPairs(L *lua.State) int {
	// See Lua >=5.2 source code.
	if L.GetMetaField(1, "__pairs") {
		L.PushValue(1)
		L.Call(1, 3)
		return 3
	}

	L.CheckType(1, lua.LUA_TTABLE)
	L.PushGoFunction(pairsAux)
	L.PushValue(1)
	L.PushNil()
	return 3
}
示例#18
0
文件: luar.go 项目: kdar/luar
// copy a Go slice to a Lua table
func CopySliceToTable(L *lua.State, vslice reflect.Value) int {
	if vslice.IsValid() && vslice.Type().Kind() == reflect.Slice {
		n := vslice.Len()
		L.CreateTable(n, 0)
		for i := 0; i < n; i++ {
			L.PushInteger(int64(i + 1))
			GoToLua(L, nil, vslice.Index(i))
			L.SetTable(-3)
		}
		return 1
	} else {
		L.PushNil()
		L.PushString("not a slice!")
	}
	return 2
}
示例#19
0
文件: luar.go 项目: kdar/luar
// copy a Go map to a Lua table
func CopyMapToTable(L *lua.State, vmap reflect.Value) int {
	if vmap.IsValid() && vmap.Type().Kind() == reflect.Map {
		n := vmap.Len()
		L.CreateTable(0, n)
		for _, key := range vmap.MapKeys() {
			val := vmap.MapIndex(key)
			GoToLua(L, nil, key)
			GoToLua(L, nil, val)
			L.SetTable(-3)
		}
		return 1
	} else {
		L.PushNil()
		L.PushString("not a map!")
	}
	return 2
}
示例#20
0
文件: luar.go 项目: imvu/Tetra
func slice__ipairs(L *lua.State) int {
	s, _ := valueOfProxy(L, 1)
	n := s.Len()
	idx := -1
	iter := func(L *lua.State) int {
		idx++
		if idx == n {
			L.PushNil()
			return 1
		}
		GoToLua(L, nil, valueOf(idx+1), false) // report as 1-based index
		val := s.Index(idx)
		GoToLua(L, nil, val, false)
		return 2
	}
	L.PushGoFunction(iter)
	return 1
}
示例#21
0
文件: luar.go 项目: imvu/Tetra
func map__pairs(L *lua.State) int {
	m, _ := valueOfProxy(L, 1)
	keys := m.MapKeys()
	idx := -1
	n := m.Len()
	iter := func(L *lua.State) int {
		idx++
		if idx == n {
			L.PushNil()
			return 1
		}
		GoToLua(L, nil, keys[idx], false)
		val := m.MapIndex(keys[idx])
		GoToLua(L, nil, val, false)
		return 2
	}
	L.PushGoFunction(iter)
	return 1
}
示例#22
0
文件: luar.go 项目: kdar/luar
// return the Lua table at 'idx' as a copied Go map. If 't' is nil then the map
// type is map[string]interface{}
func CopyTableToMap(L *lua.State, t reflect.Type, idx int) interface{} {
	if t == nil {
		t = reflect.TypeOf(tmap)
	}
	te, tk := t.Elem(), t.Key()
	m := reflect.MakeMap(t)
	L.PushNil()
	if idx < 0 {
		idx--
	}
	for L.Next(idx) != 0 {
		// key at -2, value at -1
		key := valueOf(LuaToGo(L, tk, -2))
		val := valueOf(LuaToGo(L, te, -1))
		m.SetMapIndex(key, val)
		L.Pop(1)
	}
	return m.Interface()
}
示例#23
0
文件: luar.go 项目: stevedonovan/luar
func copyMapToTable(L *lua.State, vmap reflect.Value, visited visitor) int {
	if vmap.IsValid() && vmap.Type().Kind() == reflect.Map {
		n := vmap.Len()
		L.CreateTable(0, n)
		visited.mark(vmap)
		for _, key := range vmap.MapKeys() {
			v := vmap.MapIndex(key)
			goToLua(L, nil, key, false, visited)
			if isNil(v) {
				v = nullv
			}
			goToLua(L, nil, v, true, visited)
			L.SetTable(-3)
		}
		return 1
	}
	L.PushNil()
	L.PushString("not a map!")
	return 2
}
示例#24
0
文件: luar.go 项目: yinlei/luar
// Copy matching Lua table entries to a struct, given the struct type
// and the index on the Lua stack.
func CopyTableToStruct(L *lua.State, t reflect.Type, idx int) interface{} {
	was_ptr := t.Kind() == reflect.Ptr
	if was_ptr {
		t = t.Elem()
	}
	s := reflect.New(t) // T -> *T
	ref := s.Elem()

	// Associate Lua keys with Go fields: tags have priority over matching field
	// name.
	fields := map[string]string{}
	st := ref.Type()
	for i := 0; i < ref.NumField(); i++ {
		field := st.Field(i)
		tag := field.Tag.Get("lua")
		if tag != "" {
			fields[tag] = field.Name
			continue
		}
		fields[field.Name] = field.Name
	}

	L.PushNil()
	if idx < 0 {
		idx--
	}
	for L.Next(idx) != 0 {
		key := L.ToString(-2)
		f := ref.FieldByName(fields[key])
		if f.CanSet() && f.IsValid() {
			val := luaToGoValue(L, f.Type(), -1)
			f.Set(val)
		}
		L.Pop(1)
	}
	if was_ptr {
		return s.Interface()
	}
	return s.Elem().Interface()
}
示例#25
0
文件: luar.go 项目: imvu/Tetra
// Return the Lua table at 'idx' as a copied Go map. If 't' is nil then the map
// type is map[string]interface{}
func CopyTableToMap(L *lua.State, t reflect.Type, idx int) interface{} {
	if t == nil {
		t = tmap
	}
	te, tk := t.Elem(), t.Key()
	m := reflect.MakeMap(t)
	L.PushNil()
	if idx < 0 {
		idx--
	}
	for L.Next(idx) != 0 {
		// key at -2, value at -1
		key := luaToGoValue(L, tk, -2)
		val := luaToGoValue(L, te, -1)
		if val == nullv {
			val = reflect.Zero(te)
		}
		m.SetMapIndex(key, val)
		L.Pop(1)
	}
	return m.Interface()
}
示例#26
0
文件: luar.go 项目: yinlei/luar
// Copy a Go struct to a Lua table. nils in both slices and structs
// are represented as luar.null. Defines luar.struct2table
// Use tags to set field names.
func CopyStructToTable(L *lua.State, vstruct reflect.Value) int {
	if vstruct.IsValid() && vstruct.Type().Kind() == reflect.Struct {
		n := vstruct.NumField()
		L.CreateTable(n, 0)
		for i := 0; i < n; i++ {
			st := vstruct.Type()
			field := st.Field(i)
			key := field.Name
			tag := field.Tag.Get("lua")
			if tag != "" {
				key = tag
			}
			GoToLua(L, nil, reflect.ValueOf(key), true)
			v := vstruct.Field(i)
			GoToLua(L, nil, v, true)
			L.SetTable(-3)
		}
		return 1
	} else {
		L.PushNil()
		L.PushString("not a struct!")
	}
	return 2
}
示例#27
0
文件: luar.go 项目: imvu/Tetra
// Push a Go value 'val' of type 't' on the Lua stack.
// If we haven't been given a concrete type, use the type of the value
// and unbox any interfaces.  You can force slices and maps to be copied
// over as tables by setting 'dontproxify' to true.
func GoToLua(L *lua.State, t reflect.Type, val reflect.Value, dontproxify bool) {
	if !val.IsValid() {
		L.PushNil()
		return
	}
	if t == nil {
		t = val.Type()
	}
	if t.Kind() == reflect.Interface && !val.IsNil() { // unbox interfaces!
		val = valueOf(val.Interface())
		t = val.Type()
	}
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	kind := t.Kind()

	// underlying type is 'primitive' ? wrap it as a proxy!
	if isPrimitiveDerived(t, kind) != nil {
		makeValueProxy(L, val, cINTERFACE_META)
		return
	}

	switch kind {
	case reflect.Float64, reflect.Float32:
		{
			L.PushNumber(val.Float())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		{
			L.PushNumber(float64(val.Int()))
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		{
			L.PushNumber(float64(val.Uint()))
		}
	case reflect.String:
		{
			L.PushString(val.String())
		}
	case reflect.Bool:
		{
			L.PushBoolean(val.Bool())
		}
	case reflect.Slice:
		{
			if !dontproxify {
				makeValueProxy(L, val, cSLICE_META)
			} else {
				CopySliceToTable(L, val)
			}
		}
	case reflect.Map:
		{
			if !dontproxify {
				makeValueProxy(L, val, cMAP_META)
			} else {
				CopyMapToTable(L, val)
			}
		}
	case reflect.Struct:
		{
			if v, ok := val.Interface().(error); ok {
				L.PushString(v.Error())
			} else if v, ok := val.Interface().(*LuaObject); ok {
				v.Push()
			} else {
				if (val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface) && !val.Elem().IsValid() {
					L.PushNil()
					return
				}
				makeValueProxy(L, val, cSTRUCT_META)
			}
		}
	default:
		{
			if v, ok := val.Interface().(error); ok {
				L.PushString(v.Error())
			} else if val.IsNil() {
				L.PushNil()
			} else {
				makeValueProxy(L, val, cINTERFACE_META)
			}
		}
	}
}
示例#28
0
文件: softcode.go 项目: natmeox/mess
func pushValue(state *lua.State, value interface{}) error {
	switch v := value.(type) {
	default:
		return fmt.Errorf("An item of unknown type was included in the environment or arguments of a Lua call (skipping it): %v",
			value)
	case nil:
		log.Println("Pushing nil onto lua stack")
		state.PushNil()
	case string:
		log.Println("Pushing string onto lua stack")
		state.PushString(v)
	case int:
		log.Println("Pushing int onto lua stack")
		state.PushInteger(int64(v))
	case int64:
		log.Println("Pushing int64 onto lua stack")
		state.PushInteger(v)
	case float64:
		log.Println("Pushing float64 onto lua stack")
		state.PushNumber(v)
	case bool:
		log.Println("Pushing bool onto lua stack")
		state.PushBoolean(v)

	case map[string]interface{}:
		log.Println("Pushing map[string]interface{} onto lua stack")
		state.CreateTable(0, len(v))
		for name, value := range v {
			err := pushValue(state, value)
			if err != nil {
				// error means nothing was added to stack. So pop our new table so *we* leave nothing added to the stack.
				state.Pop(1)
				return err
			}
			state.SetField(-2, name)
		}
		// then leave the table on the stack

	case ThingType:
		// These are singleton sentinel values, so load them from Lua-land.
		state.GetGlobal("world")
		state.GetField(-1, strings.Title(v.String()))
		state.Remove(-2)

	case *Thing:
		log.Println("Pushing *Thing onto lua stack")
		return pushValue(state, v.Id)
	case ThingId:
		log.Println("Pushing ThingId onto lua stack")
		// We're pushing a ThingId, so make a new userdata for it, with the Thing metatable.
		userdata := state.NewUserdata(uintptr(unsafe.Sizeof(int64(0))))
		thingPtr := (*int64)(userdata)
		*thingPtr = int64(v)
		if !state.IsUserdata(-1) {
			log.Println("!!! HOGAD JUST PUSHED NEW USERDATA BUT IT ISN'T OMG !!!")
		}
		log.Println("Pushed ThingId", *thingPtr, "onto lua stack")

		// Now make it act like a Thing.
		state.LGetMetaTable(ThingMetaTableName) // ( udata -- udata mtbl )
		state.SetMetaTable(-2)                  // ( udata mtbl -- udata )

		// Let's just check that it's that, for sures.
		if !state.IsUserdata(-1) {
			log.Println("!!! WOOP WOOP DID NOT SET METATABLE RIGHT :( !!!")
		}
	}
	return nil
}
示例#29
0
文件: luar.go 项目: stevedonovan/luar
// TODO: Check if we really need multiple pointer levels since pointer methods
// can be called on non-pointers.
func goToLua(L *lua.State, t reflect.Type, val reflect.Value, dontproxify bool, visited visitor) {
	if !val.IsValid() {
		L.PushNil()
		return
	}

	// Unbox interface.
	if val.Kind() == reflect.Interface && !val.IsNil() {
		val = reflect.ValueOf(val.Interface())
	}

	// Follow pointers if not proxifying. We save the original pointer Value in case we proxify.
	ptrVal := val
	for val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if !val.IsValid() {
		L.PushNil()
		return
	}

	// As a special case, we always proxify nullv, the empty element for slices and maps.
	if val.CanInterface() && val.Interface() == nullv.Interface() {
		makeValueProxy(L, val, cInterfaceMeta)
		return
	}

	switch val.Kind() {
	case reflect.Float64, reflect.Float32:
		if !dontproxify && predeclaredScalarType(val.Type()) != nil {
			makeValueProxy(L, ptrVal, cNumberMeta)
		} else {
			L.PushNumber(val.Float())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if !dontproxify && predeclaredScalarType(val.Type()) != nil {
			makeValueProxy(L, ptrVal, cNumberMeta)
		} else {
			L.PushNumber(float64(val.Int()))
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if !dontproxify && predeclaredScalarType(val.Type()) != nil {
			makeValueProxy(L, ptrVal, cNumberMeta)
		} else {
			L.PushNumber(float64(val.Uint()))
		}
	case reflect.String:
		if !dontproxify && predeclaredScalarType(val.Type()) != nil {
			makeValueProxy(L, ptrVal, cStringMeta)
		} else {
			L.PushString(val.String())
		}
	case reflect.Bool:
		if !dontproxify && predeclaredScalarType(val.Type()) != nil {
			makeValueProxy(L, ptrVal, cInterfaceMeta)
		} else {
			L.PushBoolean(val.Bool())
		}
	case reflect.Complex128, reflect.Complex64:
		makeValueProxy(L, ptrVal, cComplexMeta)
	case reflect.Array:
		// It needs be a pointer to be a proxy, otherwise values won't be settable.
		if !dontproxify && ptrVal.Kind() == reflect.Ptr {
			makeValueProxy(L, ptrVal, cSliceMeta)
		} else {
			// See the case of struct.
			if ptrVal.Kind() == reflect.Ptr && visited.push(ptrVal) {
				return
			}
			copySliceToTable(L, ptrVal, visited)
		}
	case reflect.Slice:
		if !dontproxify {
			makeValueProxy(L, ptrVal, cSliceMeta)
		} else {
			if visited.push(val) {
				return
			}
			copySliceToTable(L, val, visited)
		}
	case reflect.Map:
		if !dontproxify {
			makeValueProxy(L, ptrVal, cMapMeta)
		} else {
			if visited.push(val) {
				return
			}
			copyMapToTable(L, val, visited)
		}
	case reflect.Struct:
		if !dontproxify && ptrVal.Kind() == reflect.Ptr {
			if ptrVal.CanInterface() {
				switch v := ptrVal.Interface().(type) {
				case error:
					L.PushString(v.Error())
				case *LuaObject:
					v.Push()
				default:
					makeValueProxy(L, ptrVal, cStructMeta)
				}
			} else {
				makeValueProxy(L, ptrVal, cStructMeta)
			}
		} else {
			// Use ptrVal instead of val to detect cycles from the very first element, if a pointer.
			if ptrVal.Kind() == reflect.Ptr && visited.push(ptrVal) {
				return
			}
			copyStructToTable(L, ptrVal, visited)
		}
	case reflect.Chan:
		makeValueProxy(L, ptrVal, cChannelMeta)
	case reflect.Func:
		L.PushGoFunction(goLuaFunc(L, val))
	default:
		if v, ok := val.Interface().(error); ok {
			L.PushString(v.Error())
		} else if val.IsNil() {
			L.PushNil()
		} else {
			makeValueProxy(L, ptrVal, cInterfaceMeta)
		}
	}
}
示例#30
0
文件: luar.go 项目: EncoreJiang/luar
func register(L *lua.State, table string, values Map, convertFun bool) {
	pop := true
	if table == "*" {
		pop = false
	} else if len(table) > 0 {
		L.GetGlobal(table)
		if L.IsNil(-1) {
			L.NewTable()
			L.SetGlobal(table)
			L.GetGlobal(table)
		}
	} else {
		L.GetGlobal("_G")
	}
	for name, val := range values {
		t := reflect.TypeOf(val)
		if t.Kind() == reflect.Func {
			if convertFun {
				L.PushGoFunction(GoLuaFunc(L, val))
			} else {
				lf := val.(func(*lua.State) int)
				L.PushGoFunction(lf)
			}
		} else {
			GoToLua(L, t, valueOf(val), false)
		}
		L.SetField(-2, name)

		if t.Kind() == reflect.Func {
			var lf func(*lua.State) int
			if convertFun {
				lf = GoLuaFunc(L, val)
			} else {
				lf = val.(func(*lua.State) int)
			}
			L.PushGoFunction(func(L *lua.State) (ret int) {
				defer func() {
					if err2 := recover(); err2 != nil {
						GoToLua(L, typeof(err2), valueOf(err2), false)
						ret = 1
						return
					}
				}()

				ret = lf(L)
				pos := L.GetTop() - ret + 1
				L.PushNil()
				L.Insert(pos)

				for i := 0; i < L.GetTop(); i++ {
					fmt.Println(L.Typename(int(L.Type(i + 1))))
				}
				return ret + 1
			})
			L.SetField(-2, "safe_"+name)
		}
	}
	if pop {
		L.Pop(1)
	}
}