Beispiel #1
0
Datei: lua.go Projekt: reusee/lua
// 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
}
Beispiel #2
0
Datei: core.go Projekt: vron/lua
func Tostring(s *State, index int) string {
	var l C.size_t
	cs := C.lua_tolstring((*C.lua_State)(s),
		C.int(index), &l)
	// Remake this into a string!
	return C.GoStringN(cs, C.int(l))
}
Beispiel #3
0
// Converts the Lua value at the given valid index to a Go
// string. The Lua value must be a string or a number; otherwise,
// the function returns an empty string. If the value is a number, then
// Tostring also changes the actual value in the stack to a string. (This
// change confuses Next when Tostring is applied to keys during a table
// traversal).  The string always has a zero ('\0') after its last
// character (as in C), but can contain other zeros in its body.
func (this *State) Tostring(index int) string {
	str := C.lua_tolstring(this.luastate, C.int(index), nil)
	if str == nil {
		return ""
	}
	return C.GoString(str)
}
Beispiel #4
0
func (state State) getStructField(structPtr reflect.Value, lkey C.int) (ret int, err error) {
	L := state.L
	vm := state.VM
	structValue := structPtr.Elem()
	t := structValue.Type()
	info := vm.findStruct(t)
	if info == nil {
		return -1, fmt.Errorf("can not index a solid struct")
	}

	ltype := int(C.lua_type(L, lkey))
	if ltype != C.LUA_TSTRING {
		return -1, fmt.Errorf("field key of struct must be a string")
	}

	//
	//key := stringFromLua(L, lkey)
	//fld, ok := info.fields[key]
	//

	// <hack> using string pstr cache
	pstr := C.lua_tolstring(L, lkey, nil)
	// </hack>
	fld, ok := info.cache[pstr]
	if !ok {
		key := stringFromLua(L, lkey)
		return -1, fmt.Errorf("not such field `%v'", key)
	}

	value := getStructFieldValue(structValue, fld)
	state.goToLuaValue(value)
	return 1, nil
}
Beispiel #5
0
// Initializes the Lua context and compiles the source code.
func (e *ExecutionEngine) init() error {
	if e.state != nil {
		return nil
	}

	// Initialize the state and open the libraries.
	e.state = C.luaL_newstate()
	if e.state == nil {
		return errors.New("Unable to initialize Lua context.")
	}
	C.luaL_openlibs(e.state)

	// Generate the header file.
	err := e.generateHeader()
	if err != nil {
		e.Destroy()
		return err
	}

	// Compile the script.
	e.fullSource = fmt.Sprintf("%v\n%v", e.header, e.source)
	source := C.CString(e.fullSource)
	defer C.free(unsafe.Pointer(source))
	ret := C.luaL_loadstring(e.state, source)
	if ret != 0 {
		defer e.Destroy()
		errstring := C.GoString(C.lua_tolstring(e.state, -1, nil))
		return fmt.Errorf("skyd.ExecutionEngine: Syntax Error: %v", errstring)
	}

	// Run script once to initialize.
	ret = C.lua_pcall(e.state, 0, 0, 0)
	if ret != 0 {
		defer e.Destroy()
		errstring := C.GoString(C.lua_tolstring(e.state, -1, nil))
		return fmt.Errorf("skyd.ExecutionEngine: Init Error: %v", errstring)
	}

	// Setup cursor.
	err = e.initCursor()
	if err != nil {
		e.Destroy()
		return err
	}

	return nil
}
Beispiel #6
0
func (sinfo *structInfo) makeFieldsIndexCache(vm *VM) {
	L := vm.globalL
	sinfo.cache = make(map[*C.char]*structField, len(sinfo.fields))
	sinfo.lref = make(map[string]int, len(sinfo.fields))
	for key, field := range sinfo.fields {
		pushStringToLua(L, key)
		pstr := C.lua_tolstring(L, -1, nil)
		sinfo.cache[pstr] = field
		sinfo.lref[key] = int(C.luaL_ref(L, C.LUA_REGISTRYINDEX))
	}
}
Beispiel #7
0
Datei: lgo.go Projekt: reusee/lgo
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)
}
Beispiel #8
0
func packLuaString(out io.Writer, state State, object int) (n int, err error) {
	var cslen C.size_t
	cs := C.lua_tolstring(state.L, C.int(object), &cslen)

	// <HACK> pretend a []byte slice to avoid intermediate buffer
	slhead := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(cs)),
		Len:  int(cslen), Cap: int(cslen),
	}
	pslice := (*[]byte)(unsafe.Pointer(&slhead))
	// </HACK>

	return P.PackRaw(out, *pslice)
}
Beispiel #9
0
// Executes an aggregation over the iterator.
func (e *ExecutionEngine) Aggregate() (interface{}, error) {
	functionName := C.CString("sky_aggregate")
	defer C.free(unsafe.Pointer(functionName))

	C.lua_getfield(e.state, -10002, functionName)
	C.lua_pushlightuserdata(e.state, unsafe.Pointer(e.cursor))
	rc := C.lua_pcall(e.state, 1, 1, 0)
	if rc != 0 {
		luaErrString := C.GoString(C.lua_tolstring(e.state, -1, nil))
		fmt.Println(e.FullAnnotatedSource())
		return nil, fmt.Errorf("skyd.ExecutionEngine: Unable to aggregate: %s", luaErrString)
	}

	return e.decodeResult()
}
Beispiel #10
0
func luaUnpackFromString(state State) int {
	// arg 1 is func udata itself
	var cslen C.size_t
	cs := C.lua_tolstring(state.L, C.int(2), &cslen)

	// <HACK> pretend a []byte slice to avoid intermediate buffer
	slhead := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(cs)),
		Len:  int(cslen), Cap: int(cslen),
	}
	pslice := (*[]byte)(unsafe.Pointer(&slhead))
	// </HACK>

	reader := bytes.NewReader(*pslice)
	return UnpackToLua(reader, state)
}
Beispiel #11
0
Datei: lua.go Projekt: reusee/lua
// 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
}
Beispiel #12
0
// Decodes the result from a function into a Go object.
func (e *ExecutionEngine) decodeResult() (interface{}, error) {
	// Encode Lua object into msgpack.
	rc := C.mp_pack(e.state)
	if rc != 1 {
		return nil, errors.New("skyd.ExecutionEngine: Unable to msgpack decode Lua result")
	}
	sz := C.size_t(0)
	ptr := C.lua_tolstring(e.state, -1, (*C.size_t)(&sz))
	str := C.GoStringN(ptr, (C.int)(sz))
	C.lua_settop(e.state, -(1)-1) // lua_pop()

	// Decode msgpack into a Go object.
	var ret interface{}
	decoder := msgpack.NewDecoder(bytes.NewBufferString(str), nil)
	err := decoder.Decode(&ret)
	if err != nil {
		return nil, err
	}

	return ret, nil
}
Beispiel #13
0
// Executes an merge over the iterator.
func (e *ExecutionEngine) Merge(results interface{}, data interface{}) (interface{}, error) {
	functionName := C.CString("sky_merge")
	defer C.free(unsafe.Pointer(functionName))

	C.lua_getfield(e.state, -10002, functionName)
	err := e.encodeArgument(results)
	if err != nil {
		return results, err
	}
	err = e.encodeArgument(data)
	if err != nil {
		return results, err
	}
	rc := C.lua_pcall(e.state, 2, 1, 0)
	if rc != 0 {
		luaErrString := C.GoString(C.lua_tolstring(e.state, -1, nil))
		fmt.Println(e.FullAnnotatedSource())
		return results, fmt.Errorf("skyd.ExecutionEngine: Unable to merge: %s", luaErrString)
	}

	return e.decodeResult()
}
Beispiel #14
0
// Initializes the cursor used by the script.
func (e *ExecutionEngine) initCursor() error {
	// Create the cursor.
	minPropertyId, maxPropertyId := e.propertyFile.NextIdentifiers()
	e.cursor = C.sky_cursor_new((C.int32_t)(minPropertyId), (C.int32_t)(maxPropertyId))
	e.cursor.context = unsafe.Pointer(e)
	C.executionEngine_setNextObjectFunc(unsafe.Pointer(e.cursor))

	// Initialize the cursor from within Lua.
	functionName := C.CString("sky_init_cursor")
	defer C.free(unsafe.Pointer(functionName))

	C.lua_getfield(e.state, -10002, functionName)
	C.lua_pushlightuserdata(e.state, unsafe.Pointer(e.cursor))
	//fmt.Printf("%s\n\n", e.FullAnnotatedSource())
	rc := C.lua_pcall(e.state, 1, 0, 0)
	if rc != 0 {
		luaErrString := C.GoString(C.lua_tolstring(e.state, -1, nil))
		return fmt.Errorf("Unable to init cursor: %s", luaErrString)
	}

	return nil
}
Beispiel #15
0
Datei: lgo.go Projekt: reusee/lgo
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)))
	}
}
Beispiel #16
0
//export golua_interface_newindex_callback
func golua_interface_newindex_callback(Li interface{}, iid uint, field_name_cstr *C.char) int {
	L := Li.(*State)
	iface := L.registry[iid]
	ifacevalue := reflect.ValueOf(iface).Elem()

	field_name := C.GoString(field_name_cstr)

	fval := ifacevalue.FieldByName(field_name)

	if fval.Kind() == reflect.Ptr {
		fval = fval.Elem()
	}

	luatype := LuaValType(C.lua_type(L.s, 3))

	switch fval.Kind() {
	case reflect.Bool:
		if luatype == LUA_TBOOLEAN {
			fval.SetBool(int(C.lua_toboolean(L.s, 3)) != 0)
			return 1
		} else {
			L.PushString("Wrong assignment to field " + field_name)
			return -1
		}

	case reflect.Int:
		fallthrough
	case reflect.Int8:
		fallthrough
	case reflect.Int16:
		fallthrough
	case reflect.Int32:
		fallthrough
	case reflect.Int64:
		if luatype == LUA_TNUMBER {
			fval.SetInt(int64(C.lua_tointeger(L.s, 3)))
			return 1
		} else {
			L.PushString("Wrong assignment to field " + field_name)
			return -1
		}

	case reflect.Uint:
		fallthrough
	case reflect.Uint8:
		fallthrough
	case reflect.Uint16:
		fallthrough
	case reflect.Uint32:
		fallthrough
	case reflect.Uint64:
		if luatype == LUA_TNUMBER {
			fval.SetUint(uint64(C.lua_tointeger(L.s, 3)))
			return 1
		} else {
			L.PushString("Wrong assignment to field " + field_name)
			return -1
		}

	case reflect.String:
		if luatype == LUA_TSTRING {
			fval.SetString(C.GoString(C.lua_tolstring(L.s, 3, nil)))
			return 1
		} else {
			L.PushString("Wrong assignment to field " + field_name)
			return -1
		}

	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		if luatype == LUA_TNUMBER {
			fval.SetFloat(float64(C.lua_tonumber(L.s, 3)))
			return 1
		} else {
			L.PushString("Wrong assignment to field " + field_name)
			return -1
		}
	}

	L.PushString("Unsupported type of field " + field_name + ": " + fval.Type().String())
	return -1
}
Beispiel #17
0
func (L *State) ToString(index int) string {
	var size C.size_t
	//C.GoString(C.lua_tolstring(L.s, C.int(index), &size));
	return C.GoString(C.lua_tolstring(L.s, C.int(index), &size))
}
Beispiel #18
0
func (L *State) ToBytes(index int) []byte {
	var size C.size_t
	b := C.lua_tolstring(L.s, C.int(index), &size)
	return C.GoBytes(unsafe.Pointer(b), C.int(size))
}
Beispiel #19
0
func (L *State) getString(i int) (ret string) {
	return C.GoString(C.lua_tolstring(L.s, C.int(i+1), nil))
}
Beispiel #20
0
Datei: lgo.go Projekt: 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
}
Beispiel #21
0
func stringFromLua(L *C.lua_State, lvalue C.int) string {
	var cslen C.size_t
	cs := C.lua_tolstring(L, lvalue, &cslen)
	return C.GoStringN(cs, C.int(cslen))
}
Beispiel #22
0
Datei: lua.go Projekt: reusee/lua
func (l *Lua) getStackTraceback() string {
	C.lua_getfield(l.State, C.LUA_GLOBALSINDEX, cstr("debug"))
	C.lua_getfield(l.State, -1, cstr("traceback"))
	C.lua_call(l.State, 0, 1)
	return C.GoString(C.lua_tolstring(l.State, -1, nil))
}
Beispiel #23
0
Datei: lua.go Projekt: szll/golua
// lua_tostring
func (L *State) ToString(index int) string {
	var size C.size_t
	r := C.lua_tolstring(L.s, C.int(index), &size)
	return C.GoStringN(r, C.int(size))
}
Beispiel #24
0
Datei: lua.go Projekt: 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
}