1

I've the following lua script, in which I use a C++ function that needs to read both keys and values of a nested table:

local scenariolist = {
   scenarios = {
      'scenario1',
      'scenario3',
      'scenario2'
   },
   result = true,
   message = 'test message'
}

my.sendfromscenariolist(scenariolist)

This is my C++ function that's executed when calling sendfromscenariolist:

int ScenarioFunction(lua_State* L) {
  int nargs = lua_gettop(L);
  if (nargs != 1) {
    return 0;
  }
  int type = lua_type(L, 1);
  if (type != LUA_TTABLE) {
    return 0;
  }
  ParseScenarioTable(L);
  return 0;
}


void ParseScenarioTable(lua_State* L) {

  lua_pushnil(L);
  while (lua_next(L, -2) != 0) {
    if (lua_istable(L, -1)) {
      ParseScenarioTable(L);
      std::cout << "Key: " << "key" << ", Value is table" << std::endl;
    }
    else if (lua_isstring(L, -1)) {
      std::string x = lua_tostring(L, -1);
      std::cout << "Key: " << "key" << ", Value: " << x << std::endl;
      int i = 0;
    }
    else if (lua_isboolean(L, -1)) {
      bool x = lua_toboolean(L, -1);
      int i = 0;
      std::cout << "Key: " << "key" << ", Value: " << x << std::endl;
    }
    lua_pop(L, 1);
  }
}

This function read only values and it works, when I run it in the console I obtain:

Key: key, Value: 1
Key: key, Value: scenario1
Key: key, Value: scenario3
Key: key, Value: scenario2
Key: key, Value is table
Key: key, Value: test message

The problem is that I'm not able to read also keys of nested table elements. I've changed my code with this:

int ScenarioFunction(lua_State* L) {
  int nargs = lua_gettop(L);
  if (nargs != 1) {
    return 0;
  }
  int type = lua_type(L, 1);
  if (type != LUA_TTABLE) {
    return 0;
  }
  ParseScenarioTable(L);
  return 0;
}


void ParseScenarioTable(lua_State* L) {

  lua_pushnil(L);
  while (lua_next(L, -2) != 0) {
    if (lua_istable(L, -1)) {
      std::string key = lua_tostring(L, -2);
      ParseScenarioTable(L);
      std::cout << "Key: " << key << ", Value is table" << std::endl;
    }
    else if (lua_isstring(L, -1)) {
      std::string key = lua_tostring(L, -2);
      std::string x = lua_tostring(L, -1);
      std::cout << "Key: " << key << ", Value: " << x << std::endl;
      int i = 0;
    }
    else if (lua_isboolean(L, -1)) {
      std::string key = lua_tostring(L, -2);
      bool x = lua_toboolean(L, -1);
      int i = 0;
      std::cout << "Key: " << key << ", Value: " << x << std::endl;
    }
    lua_pop(L, 1);
  }
}

But if I try to read the keys, the program will broke and I obtain an error: This is the output of my program:

Key: result, Value: 1
Key: 1, Value: scenario1
[2023-09-01 16:17:03.391093][error]: Error when running the script. Error is: invalid key to 'next'

where invalid key to 'next' is the error string of lua.

What I'm doing wrong? How can I read both keys and values?

1 Answer 1

3

The problem is here:

std::string key = lua_tostring(L, -2);

The lua_tostring modifies its argument: it replaces number 1 with string "1" at the API stack index -2, so following lua_next is unable to continue traversing the table as it receives non-existing key "1" instead of existing 1.
This behavior is described in the manual.

Solution:
Create additional temporary stack slot for the value to be modified by lua_tostring.
Replace

std::string key = lua_tostring(L, -2);

with

lua_pushvalue(L, -2);
std::string key = lua_tostring(L, -1);
lua_pop(L, 1);
Sign up to request clarification or add additional context in comments.

Comments

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.