1

I'm trying to pass table with subtable to Lua function as argument from C++.

Here's my code that doesn't work but shows what I'm trying to do.

    class DragInfo{
    public:
        std::vector <std::string> files;
        glm::vec2 position;
    };

    //a callback that passes DragInfo to a Lua function as a table which has 2 subtables
    void callDragged(DragInfo &info)
    {
        lua_getglobal(L, "dragged");
        if (!lua_isfunction(L, -1))
        {
            lua_pop(L, 1);
            return;
        }
        lua_newtable(L);
        for (size_t i = 0; i < info.files.size(); ++i)
        {
            lua_pushinteger(L, static_cast<lua_Integer>(i + 1));
            lua_pushstring(L, info.files[i].c_str());
            lua_settable(L, -3);
        }
        lua_pushnumber(L, static_cast<lua_Number>(info.position.x));
        lua_setfield(L, -2, "x");
        lua_pushnumber(L, static_cast<lua_Number>(info.position.y));
        lua_setfield(L, -2, "y");

        if (lua_pcall(L, 1, 0, 0))
            std::cout << "Error : " <<  lua_tostring(L, -1) << std::endl;
    }

And in Lua, I want to be able to, for example..

function dragged(info)
   for i=1, #info.files do
       print("dragged filename: " .. info.files[i])
   end
   print("dragged position: " .. info.position.x .. " " .. info.position.y)
end

And the result can be something like

dragged filename: background.jpg
dragged filename: apple.png
dragged position: 425 32

How should I correct my C++ function so it works properly like the example?

1 Answer 1

2

It is rather simple. Just create subtables and assign those to fields in the outermost table.

I also recommend that you raise an error if dragged is not a function rather than doing nothing.

// a callback that passes DragInfo to a Lua function as a table which has 2
// subtables
void callDragged(DragInfo &info) {
    lua_getglobal(L, "dragged");
    if (!lua_isfunction(L, -1)) {
        lua_pop(L, 1);
        lua_pushstring(L, "argument is not a function");
        lua_error(L);
        return;
    }

    // outermost table
    lua_newtable(L);

    // subtable "files"
    lua_newtable(L);
    for (size_t i = 0; i < info.files.size(); ++i) {
        lua_pushinteger(L, i + 1);
        lua_pushstring(L, info.files[i].c_str());
        lua_settable(L, -3);
    }
    lua_setfield(L, -2, "files");

    // subtable "position"
    lua_newtable(L);
    lua_pushnumber(L, info.position.x);
    lua_setfield(L, -2, "x");
    lua_pushnumber(L, info.position.y);
    lua_setfield(L, -2, "y");
    lua_setfield(L, -2, "position");

    if (lua_pcall(L, 1, 0, 0) != 0) {
        std::cout << "Error : " << lua_tostring(L, -1) << '\n';
        lua_pop(L, 1);
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much for your answer. Don't I need to put lua_pop(L, 1) inside if (!lua_isfunction(L, -1)) before return?
@ZackLee Since the error ends the program it doesn't really matter but technically yes. I put it there now, just in case the function is invoked within pcall.
Thanks! Last question: does calling lua_setglobal(L, "name") also requires lua_pop(L,1) afterwards?
@ZackLee “Pops a value from the stack and sets it as the new value of global” lua.org/manual/5.3/manual.html#lua_setglobal

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.