Zack Lee
Zack Lee

Reputation: 3044

Dynamically find out the number of return values of Lua function()?

I wonder if it is possible to dynamically find out the number of return values of Lua function in C++.

For example, I can pass and return values to/from Lua function in C++ like this.

/* push functions and arguments */
lua_getglobal(L, "f");  /* function to be called */
lua_pushnumber(L, x);   /* push 1st argument */
lua_pushnumber(L, y);   /* push 2nd argument */

/* do the call (2 arguments, 1 result) */
if (lua_pcall(L, 2, 1, 0) != 0)
    error(L, "error running function `f': %s", lua_tostring(L, -1));

/* do something with the result */

As you can see, it expects 1 returned value from Lua function. So if user returns more(or less) than 1 value in Lua function, it will not work properly.

Is there any possible solution to detect the number of returned values from Lua function in advance so I can dynamically process the returned values in C++?

Upvotes: 0

Views: 1861

Answers (2)

Henri Menke
Henri Menke

Reputation: 10939

This is an extension to the existing answer, outlining a possible implementation. I will remove this answer as soon as an implementation example is added to the existing one.

#include <iostream>

#include <lua.hpp>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " <script.lua>\n";
        return 1;
    }

    lua_State * L = luaL_newstate();
    luaL_openlibs(L);

    if (luaL_dofile(L, argv[1]) != 0) {
        std::cerr << "lua: " << lua_tostring(L, -1) << '\n';
        lua_close(L);
        return 1;
    }

    int stack_size = lua_gettop(L);

    lua_getglobal(L, "f");
    lua_pushnumber(L, 1);
    lua_pushnumber(L, 2);

    if (lua_pcall(L, 2, LUA_MULTRET, 0) != 0) {
        std::cerr << "lua: " << lua_tostring(L, -1) << '\n';
        lua_close(L);
        return 1;
    }

    int num_returns = lua_gettop(L) - stack_size;
    std::cout << num_returns << " values returned\n";

    lua_close(L);
}
function f(x,y)
    return 1,2,3,"Hello World",{},function() end
end
6 values returned

Upvotes: 3

https://www.lua.org/manual/5.3/manual.html#lua_call (also applies to lua_pcall):

The number of results is adjusted to nresults, unless nresults is LUA_MULTRET. In this case, all results from the function are pushed; Lua takes care that the returned values fit into the stack space, but it does not ensure any extra space in the stack. The function results are pushed onto the stack in direct order (the first result is pushed first), so that after the call the last result is on the top of the stack.

So it looks like you can save the previous stack top (use lua_gettop), subtract the number of arguments and 1 for function itself, do the call, then get the stack top again and the difference is the number of return values. Remember to pass LUA_MULTRET for nresults.

Upvotes: 2

Related Questions