Search code examples
c++lualua-tablelua-api

Moving a lua table in C api


I'm attempting to move a table to another table using the lua C api. For instance, I have a table with this structure:

a[b][c][d][e] = value

I want to move table d this to be under a[b], which I could accomplish in Lua like:

a[b][d] = a[b][c][d]
a[b][c][d] = nil

My current approach is to load on the stack the a[b][c][d] table, so the stack looks like:

Index  Value
-1     d table
-2     c table
-3     b table
-4     a table

Then load a[b] onto the stack, so it looks like:

Index  Value
-1     b table
-2     a table
-3     d table
-4     c table
-5     b table
-6     a table

Then put d's key onto the stack, and insert d's key and table b under table d, so the stack is:

Index  Value
-1     d table
-2     d key
-3     b table
-4     a table
-5     c table
-6     b table
-7     a table

Then I use lua_settable(L, -3), to do b[d] = d.

This approach works for non-table keys, but fails for keys which are tables. So it will fail for something like:

a[b][c][{}][d] = value
a[b] = a[b][c][{}][d]

Note, I know in the above it will fail in the lua given above because the key would be a new lua table, I just wanted to illustrate it.

I've tried going down the table parents (so doing a[b] = b, lua_setglobal(L, a)) without any luck either. Does anyone know where I'm going wrong here?

Edit: A small code snippet on how I push keys/values onto the stack. The goal here is to move a table from one table structure to another (or as I call it in the code, reparent it)

http://pastebin.com/Y4540Wss

Solution:

The issue was the table has some metatable function which prevented changes to the table (in essence, the person making the script had a config table where the structure was important, thus causing this issue.)


Solution

  • If I understand your description correctly, this Lua code does what you want:

    local ab = a[b]
    ab[d], ab[c][d] = ab[c][d], nil
    

    As for implementing that in the Lua C API, lua2c is helpful with this machine translation:

    enum { lc_nformalargs = 0 };
    const int lc_nactualargs = lua_gettop(L);
    const int lc_nextra = (lc_nactualargs - lc_nformalargs);
    
    /* local ab = a[b] */
    lua_getfield(L,LUA_ENVIRONINDEX,"a");
    lua_getfield(L,LUA_ENVIRONINDEX,"b");
    lua_gettable(L,-2);
    lua_remove(L,-2);
    assert(lua_gettop(L) - lc_nextra == 1);
    
    /* ab[d], ab[c][d] = ab[c][d], nil */
    lua_getfield(L,LUA_ENVIRONINDEX,"c");
    lua_gettable(L,(1 + lc_nextra));
    lua_getfield(L,LUA_ENVIRONINDEX,"d");
    lua_gettable(L,-2);
    lua_remove(L,-2);
    lua_pushnil(L);
    lua_getfield(L,LUA_ENVIRONINDEX,"c");
    lua_gettable(L,(1 + lc_nextra));
    lua_insert(L,-2);
    lua_getfield(L,LUA_ENVIRONINDEX,"d");
    lua_insert(L,-2);
    lua_settable(L,-3);
    lua_pop(L,1);
    lua_getfield(L,LUA_ENVIRONINDEX,"d");
    lua_insert(L,-2);
    lua_settable(L,(1 + lc_nextra));
    assert(lua_gettop(L) - lc_nextra == 1);
    return 0;
    

    I have yet to develop a readable way of writing stack operations.