Я пытаюсь использовать Lua для конфигурации приложения C ++, и у меня возникают проблемы при создании полезных сообщений, когда что-то не так в конфигурации, а не синтаксис Lua.
Например, предположим, что приведенная ниже допустимая конфигурация:
foo = { a = 0, b = 'bar' }
но пользователь на самом деле набрал это:
foo = { a = 0, c = 'bar' }
Теперь приложение знает, что foo может иметь поля a и b. Он может загрузить foo и получить значение a. Он может даже сказать, что b не установлен и использовать по умолчанию. Но я хочу обнаружить, что c присутствует и сообщить о предупреждении.
Вот выдержка из моей попытки взорваться:
static void check_table(lua_State* L)
{
lua_pushnil(L);
while ( lua_next(L, -2) )
{
// key at -2 and value at -1
if ( lua_isstring(L, -2) )
{
const char* key = lua_tostring(L, -2);
// validate here; just printing key for now
cout << key << endl;
}
lua_pop(L, 1);
}
}
Это прекрасно работает, пока таблица на самом деле не является массивом. Когда я нажимаю один из них, он умирает на второй итерации с этим:
...
1
PANIC: unprotected error in call to Lua API (invalid key to 'next')
который я приписываю этому со справочной страницы Lua:
"If the value is a number, then lua_tolstring also changes the actual value in the
stack to a string. (This change confuses lua_next when lua_tolstring is applied to
keys during a table traversal.)"
Есть ли способ обойти это? Я открыт для альтернативных подходов. В идеале сообщение может быть отправлено следующим образом:
ВНИМАНИЕ: строка conf.lua 18: таблица foo не использует ключ ‘c’, игнорируется
(API отладки Lua также не дает имя файла и номер строки, но это другая тема.)
PS: я знаю, c может быть мягким, но это также может быть опечатка. В большой конфигурации игнорирование таких вещей может привести к часам царапин на голове.
Проверка будет, вероятно, намного проще, если написано на Lua. Я имею в виду что-то вроде этого:
local template = { a="number", b="string"}
local function validate(t)
for k,v in pairs(t) do
if template[k]==nil then
print("field "..k.." cannot be present")
elseif type(v)~=template[k] then
print("field "..k.." should be a "..template[k])
end
end
end
validate{ a = 0, b = 'bar' }
validate{ a = 0, b = 42 }
validate{ a = 0 }
validate{ a = 0, c = 'bar' }
lua_isstring is defined:
LUA_API int lua_isstring (lua_State *L, int idx) {
int t = lua_type(L, idx);
return (t == LUA_TSTRING || t == LUA_TNUMBER);
}
Так что вместо:
if ( lua_isstring(L, -2) )
использовать:
if ( lua_type(L, -2) == LUA_TSTRING )