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?
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);