haze
haze

Reputation: 239

Calling lua function that returns table

I know the basics of interacting with lua and C, and I am currently trying to perform the following line of lua in c++

Func1():Func2().Table1.value1

I am trying to get the value of "value2" and use it in my C program. The following is the code I wrote to attempt to get this value in C.

int GetNumber()
{
    int retn = 0;
    g_clientlua.lua_getfield(LUA_REGISTRYINDEX, "Player");
    g_clientlua.lua_getfield(-1, "Func2");
    g_clientlua.lua_getfield(LUA_GLOBALSINDEX, "Func1");
    g_clientlua.lua_call(0, 1);
    g_clientlua.lua_call(1, 1);
    if (g_clientlua.lua_isnil(-1)) 
        return retn;
    g_clientlua.lua_getfield(-1, "Table1");
    if (g_clientlua.lua_isnil(-1)) 
        return retn;
    g_clientlua.lua_getfield(-1, "value1");
    if (g_clientlua.lua_isnil(-1)) 
        return retn;
    retn = (int)g_clientlua.lua_tointeger(-1);
}

The clientlua thing is an object that basically just allows me to call a method which calls it's lua_* function equivalent and fills the lua_state pointer parameter with a member variable that is a pointer to the lua state.

Every time I call this, it complains about me causing a lua stack leak. To solve this, I tried adding a lua_pop(3) to the end, but then it just crashes my program without reporting an error, so I assume I am doing something wrong.

Anyone have any words of wisdom for me? Kinda lost here. I doubt the above code is even written properly, how would I write the above lua call in C?

Upvotes: 4

Views: 936

Answers (2)

greatwolf
greatwolf

Reputation: 20878

The GetNumber function isn't doing exactly the same as the lua snippet you're going for. Specifically GetNumber is getting the value of "Func2" from the registry while your lua snippet is getting the value of "Func2" from the table returned by Func1(). Unless you're certain that registry.Player.Func2 == Func1().Func2 is always true, your C++ version will not have the same behavior.

Let's break down Func1():Func2().Table1.value1 into more explicit steps to help with the C translation:

  1. Get function associated with _G.Func1
  2. Call that function and get a table back
  3. Get function associated with "Func2" from the returned table in step 2
  4. Call that function and pass as argument the table from step 2. Get another table back as result

I found it helpful to track what the stack contains as a side-comment as the operations are performed:

int GetNumber()
{
    // Func1()
    gclientlua.lua_getfield(LUA_GLOBALSINDEX, "Func1");     // Func1
    g_clientlua.lua_call(0, 1);                             // {}

    // Func2( {} )
    g_clientlua.lua_getfield(-1, "Func2");                  // {}, Func2
    g_clientlua.lua_insert(-2);                             // Func2, {}
    g_clientlua.lua_call(1, 1);                             // {}

    if( g_clientlua.lua_type(-1) != LUA_TTABLE )
    {
      g_clientlua.lua_pop(1);
      return 0;
    }

    // {}.Table1
    g_clientlua.lua_getfield(-1, "Table1");                 // {}, {}(Table1)
    if( g_clientlua.lua_type(-1) != LUA_TTABLE )
    {
      g_clientlua.lua_pop(2);
      return 0;
    }

    // tonumber( Table1.value1 )
    g_clientlua.lua_getfield(-1, "value1");                 // {}, {}(Table1), value1
    int retn = g_clientlua.lua_tointeger(-1);
    g_clientlua.lua_pop(3);
    return retn;
}

Notice that GetNumber pops off all the arguments it places on the stack before returning. This ensures that GetNumber leaves the lua stack the way it was found. This can probably be automated with RAII if you're using C++.

Upvotes: 0

Etan Reisner
Etan Reisner

Reputation: 81052

You need to call Func1 before you try to get Func2 as Func2 comes from the table that Func1 returns (and not from the global table).

Then you need to call Func2 and look up Table1 in that returned value, etc.

What "stack leak" complaint are you getting? If you are calling this function from C directly then yes, you need to be sure that anything you put on the lua stack (that isn't for consumption by the caller, etc.) is popped from the lua stack before you return.

Upvotes: 2

Related Questions