Search code examples
c++lualuabind

Push some data to Lua call function


I have two files - one for executing Lua script and the script itself.

Here they are:

host.cpp:

#include <lua.hpp>
#include <iostream>

using namespace std;

int someHandler(lua_State  *l)
{
    int argc = lua_gettop(l);

    for (int i = 0; i < argc; i++)
    {
        cout << "ARG[" << i + 1 << "] = " << lua_tostring(l, i + 1) << endl;
    }

    lua_pushstring(l, "m_pi");
    //lua_pop(l, argc - 1);
    //lua_pushnumber(l, 3.14);

    return argc;
}

int main()
{
    lua_State *l = lua_open();
    luaL_openlibs(l);

    lua_register(l, "moo", someHandler);

    luaL_dofile(l, "script.lua");

    lua_close(l);

    return 0;
}

script.lua:

res = moo("hello", "world");

print(moo());

for k, v in res do
    print(k.." = "..v);
end

Compiling host.cpp with g++ host.cpp -o host.elf -I/usr/include/lua5.1 -llua5.1.

The result of running host.elf is:

ARG[1] = hello
ARG[2] = world
<\n>

while it should be:

ARG[1] = hello
ARG[2] = world
m_pi

What do i do wrong?


Solution

  • Line-by-line explanation:

    --This calls moo with two arguments
    --(ignore the assignment for now, we will come back to that)
    res = moo("hello", "world");
    

    Control transfers to C++:

    //the stack of l looks like this: ["hello", "world"]
    int someHandler(lua_State  *l)
    {
    
        int argc = lua_gettop(l); //int argc = 2;
    
        //This loop prints:
        //"ARG[1] = hello\n"
        //"ARG[2] = world\n"
        for (int i = 0; i < argc; i++)
        {
            cout << "ARG[" << i + 1 << "] = " << lua_tostring(l, i + 1) << endl;
        }
        //This pushes "m_pi" on to the stack:
        lua_pushstring(l, "m_pi");
    
        //The stack now looks like ["hello", "world", "m_pi"]
    
        //Returns 2.
        //Lua will treat this as a function which
        //returns the top two elements on the stack (["world", "m_pi"])
        return argc;
    }
    

    Control returns to lua:

    --Assigns the first result ("world") to res, discards the other results ("m_pi")
    res = moo("hello", "world");
    
    --Calls `moo` with zero arguments.
    --This time, `lua_gettop(l)` will evaluate to `0`,
    --so the for loop will not be entered,
    --and the number of results will be taken to be `0`.
    --The string pushed by `lua_pushstring(l, "m_pi")` will be discarded.
    --`moo()` returns no results, so `print` prints nothing.
    print(moo());
    
    --WTF??: res = "world", which is a string, not an expression which evaluates to
    --a loop function, a state variable, and a element variable.
    
    --The for loop will raise in an error when it 
    --attempts to call a copy of `res` (a string)
    for k, v in res do
        print(k.." = "..v);
    end