luaobject.go
func (lo *LuaObject) Call(results interface{}, args ...interface{}) error {
	L := lo.l
	// Push the callable value.
	lo.Push()
	if !L.IsFunction(-1) {
		if !L.GetMetaField(-1, "__call") {
			L.Pop(1)
			return ErrLuaObjectCallable
		}
		// We leave the __call metamethod on stack.
		L.Remove(-2)
	}

	// Push the args.
	for _, arg := range args {
		GoToLuaProxy(L, arg)
	}

	// Special case: discard the results.
	if results == nil {
		err := L.Call(len(args), 0)
		if err != nil {
			L.Pop(1)
			return err
		}
		return nil
	}

	resptr := reflect.ValueOf(results)
	if resptr.Kind() != reflect.Ptr {
		return ErrLuaObjectCallResults
	}
	res := resptr.Elem()

	switch res.Kind() {
	case reflect.Ptr:
		err := L.Call(len(args), 1)
		defer L.Pop(1)
		if err != nil {
			return err
		}
		return LuaToGo(L, -1, res.Interface())

	case reflect.Slice:
		residx := L.GetTop() - len(args)
		err := L.Call(len(args), lua.LUA_MULTRET)
		if err != nil {
			L.Pop(1)
			return err
		}

		nresults := L.GetTop() - residx + 1
		defer L.Pop(nresults)
		t := res.Type()

		// Adjust the length of the slice.
		if res.IsNil() || nresults > res.Len() {
			v := reflect.MakeSlice(t, nresults, nresults)
			res.Set(v)
		} else if nresults < res.Len() {
			res.SetLen(nresults)
		}

		for i := 0; i < nresults; i++ {
			err = LuaToGo(L, residx+i, res.Index(i).Addr().Interface())
			if err != nil {
				return err
			}
		}

	case reflect.Struct:
		exportedFields := []reflect.Value{}
		for i := 0; i < res.NumField(); i++ {
			if res.Field(i).CanInterface() {
				exportedFields = append(exportedFields, res.Field(i).Addr())
			}
		}
		nresults := len(exportedFields)
		err := L.Call(len(args), nresults)
		if err != nil {
			L.Pop(1)
			return err
		}
		defer L.Pop(nresults)
		residx := L.GetTop() - nresults + 1

		for i := 0; i < nresults; i++ {
			err = LuaToGo(L, residx+i, exportedFields[i].Interface())
			if err != nil {
				return err
			}
		}

	default:
		return ErrLuaObjectCallResults
	}

	return nil
}
func (lo *LuaObject) Call(results interface{}, args ...interface{}) error {
	L := lo.l
	// Push the callable value.
	lo.Push()
	if !L.IsFunction(-1) {
		if !L.GetMetaField(-1, "__call") {
			L.Pop(1)
			return ErrLuaObjectCallable
		}
		// We leave the __call metamethod on stack.
		L.Remove(-2)
	}

	// Push the args.
	for _, arg := range args {
		GoToLuaProxy(L, arg)
	}

	// Special case: discard the results.
	if results == nil {
		err := L.Call(len(args), 0)
		if err != nil {
			L.Pop(1)
			return err
		}
		return nil
	}

	resptr := reflect.ValueOf(results)
	if resptr.Kind() != reflect.Ptr {
		return ErrLuaObjectCallResults
	}
	res := resptr.Elem()

	switch res.Kind() {
	case reflect.Ptr:
		err := L.Call(len(args), 1)
		defer L.Pop(1)
		if err != nil {
			return err
		}
		return LuaToGo(L, -1, res.Interface())

	case reflect.Slice:
		residx := L.GetTop() - len(args)
		err := L.Call(len(args), lua.LUA_MULTRET)
		if err != nil {
			L.Pop(1)
			return err
		}

		nresults := L.GetTop() - residx + 1
		defer L.Pop(nresults)
		t := res.Type()

		// Adjust the length of the slice.
		if res.IsNil() || nresults > res.Len() {
			v := reflect.MakeSlice(t, nresults, nresults)
			res.Set(v)
		} else if nresults < res.Len() {
			res.SetLen(nresults)
		}

		for i := 0; i < nresults; i++ {
			err = LuaToGo(L, residx+i, res.Index(i).Addr().Interface())
			if err != nil {
				return err
			}
		}

	case reflect.Struct:
		exportedFields := []reflect.Value{}
		for i := 0; i < res.NumField(); i++ {
			if res.Field(i).CanInterface() {
				exportedFields = append(exportedFields, res.Field(i).Addr())
			}
		}
		nresults := len(exportedFields)
		err := L.Call(len(args), nresults)
		if err != nil {
			L.Pop(1)
			return err
		}
		defer L.Pop(nresults)
		residx := L.GetTop() - nresults + 1

		for i := 0; i < nresults; i++ {
			err = LuaToGo(L, residx+i, exportedFields[i].Interface())
			if err != nil {
				return err
			}
		}

	default:
		return ErrLuaObjectCallResults
	}

	return nil
}
// Call calls a Lua function, given the desired results and the arguments.
// 'results' must be a pointer to a pointer/struct/slice.
//
// - If a pointer, then only the first result is stored to that pointer.
//
// - If a struct with 'n' exported fields, then the first 'n' results are stored in the first 'n' exported fields.
//
// - If a slice, then all the results are stored in the slice. The slice is re-allocated if necessary.
//
// If the function returns more values than can be stored in the 'results'
// argument, they will be ignored.
//
// If 'results' is nil, results will be discarded.