44 void QuoteStringOnStack(lua_State* L) {
45 CHECK(lua_isstring(L, -1)) <<
"Top of stack is not a string value.";
46 int current_index = lua_gettop(L);
49 lua_pushglobaltable(L);
50 lua_getfield(L, -1,
"string");
53 lua_pushstring(L,
"%q");
54 lua_pushvalue(L, current_index);
58 lua_replace(L, current_index);
65 void SetDictionaryInRegistry(lua_State* L, LuaParameterDictionary* dictionary) {
66 lua_pushstring(L,
"this");
67 lua_pushlightuserdata(L, dictionary);
68 lua_settable(L, LUA_REGISTRYINDEX);
72 LuaParameterDictionary* GetDictionaryFromRegistry(lua_State* L) {
73 lua_pushstring(L,
"this");
74 lua_gettable(L, LUA_REGISTRYINDEX);
75 void* return_value = lua_isnil(L, -1) ? nullptr : lua_touserdata(L, -1);
77 CHECK(return_value !=
nullptr);
78 return reinterpret_cast<LuaParameterDictionary*
>(return_value);
82 void CheckForLuaErrors(lua_State* L,
int status) {
83 CHECK_EQ(status, 0) << lua_tostring(L, -1);
87 int LuaChoose(lua_State* L) {
88 CHECK_EQ(lua_gettop(L), 3) <<
"choose() takes (condition, a, b).";
89 CHECK(lua_isboolean(L, 1)) <<
"condition is not a boolean value.";
91 const bool condition = lua_toboolean(L, 1);
101 void PushValue(lua_State* L,
const int key) { lua_pushinteger(L, key); }
102 void PushValue(lua_State* L,
const std::string& key) {
103 lua_pushstring(L, key.c_str());
108 template <
typename T>
109 void GetValueFromLuaTable(lua_State* L,
const T& key) {
115 void CheckTableIsAtTopOfStack(lua_State* L) {
116 CHECK(lua_istable(L, -1)) <<
"Topmost item on Lua stack is not a table!";
120 template <
typename T>
121 bool HasKeyOfType(lua_State* L,
const T& key) {
122 CheckTableIsAtTopOfStack(L);
125 const bool key_not_found = lua_isnil(L, -1);
127 return !key_not_found;
133 void GetArrayValues(lua_State* L,
const std::function<
void()>& pop_value) {
136 GetValueFromLuaTable(L, idx);
137 if (lua_isnil(L, -1)) {
148 std::unique_ptr<LuaParameterDictionary>
150 const std::string& code, std::unique_ptr<FileResolver> file_resolver) {
156 const std::string& code, std::unique_ptr<FileResolver> file_resolver)
158 std::move(file_resolver)) {}
162 std::unique_ptr<FileResolver> file_resolver)
163 :
L_(luaL_newstate()),
168 SetDictionaryInRegistry(
L_,
this);
172 lua_register(
L_,
"choose", LuaChoose);
176 CheckForLuaErrors(
L_, luaL_loadstring(
L_, code.c_str()));
177 CheckForLuaErrors(
L_, lua_pcall(
L_, 0, 1, 0));
178 CheckTableIsAtTopOfStack(
L_);
183 std::shared_ptr<FileResolver> file_resolver)
184 :
L_(lua_newthread(L)),
190 CHECK(lua_isthread(L, -1));
193 CHECK(lua_istable(L, -1)) <<
"Topmost item on Lua stack is not a table!";
195 CheckTableIsAtTopOfStack(
L_);
210 CheckTableIsAtTopOfStack(
L_);
211 std::vector<std::string> keys;
214 while (lua_next(
L_, -2) != 0) {
216 if (!lua_isnumber(
L_, -1)) {
217 keys.emplace_back(lua_tostring(
L_, -1));
224 return HasKeyOfType(
L_, key);
229 GetValueFromLuaTable(
L_, key);
234 CHECK(lua_isstring(
L_, -1)) <<
"Top of stack is not a string value.";
236 QuoteStringOnStack(
L_);
239 const std::string value = lua_tostring(
L_, -1);
246 GetValueFromLuaTable(
L_, key);
251 CHECK(lua_isnumber(
L_, -1)) <<
"Top of stack is not a number value.";
252 const double value = lua_tonumber(
L_, -1);
259 GetValueFromLuaTable(
L_, key);
264 CHECK(lua_isnumber(
L_, -1)) <<
"Top of stack is not a number value.";
265 const int value = lua_tointeger(
L_, -1);
272 GetValueFromLuaTable(
L_, key);
277 CHECK(lua_isboolean(
L_, -1)) <<
"Top of stack is not a boolean value.";
278 const bool value = lua_toboolean(
L_, -1);
284 const std::string& key) {
286 GetValueFromLuaTable(
L_, key);
292 CheckTableIsAtTopOfStack(
L_);
293 std::unique_ptr<LuaParameterDictionary> value(
296 CheckTableIsAtTopOfStack(
L_);
301 const std::string& indent)
const {
302 std::string result =
"{";
303 bool dictionary_is_empty =
true;
305 const auto top_of_stack_to_string = [
this, indent,
306 &dictionary_is_empty]() -> std::string {
307 dictionary_is_empty =
false;
309 const int value_type = lua_type(
L_, -1);
310 switch (value_type) {
312 return PopBool() ?
"true" :
"false";
319 if (std::isinf(value)) {
320 return value < 0 ?
"-math.huge" :
"math.huge";
322 return std::to_string(value);
326 std::unique_ptr<LuaParameterDictionary> subdict(
328 return subdict->DoToString(indent +
" ");
331 LOG(FATAL) <<
"Unhandled type " << lua_typename(
L_, value_type);
336 for (
int i = 1; i; ++i) {
337 GetValueFromLuaTable(
L_, i);
338 if (lua_isnil(
L_, -1)) {
343 result.append(indent);
345 result.append(top_of_stack_to_string());
350 std::vector<std::string> keys =
GetKeys();
352 std::sort(keys.begin(), keys.end());
353 for (
const std::string& key : keys) {
354 GetValueFromLuaTable(
L_, key);
356 result.append(indent);
359 result.append(
" = ");
360 result.append(top_of_stack_to_string());
365 result.append(indent);
368 if (dictionary_is_empty) {
377 std::vector<double> values;
378 GetArrayValues(
L_, [&values,
this] { values.push_back(
PopDouble()); });
382 std::vector<std::unique_ptr<LuaParameterDictionary>>
384 std::vector<std::unique_ptr<LuaParameterDictionary>> values;
385 GetArrayValues(
L_, [&values,
this] {
392 std::vector<std::string> values;
399 CHECK(
HasKey(key)) <<
"Key '" << key <<
"' not in dictionary:\n" 409 for (
const auto& key :
GetKeys()) {
411 <<
"Key '" << key <<
"' was used the wrong number of times.";
413 <<
"Key '" << key <<
"' was used the wrong number of times.";
419 const int temp =
GetInt(key);
420 CHECK_GE(temp, 0) << temp <<
" is negative.";
427 CHECK_EQ(lua_gettop(L), 1);
428 CHECK(lua_isstring(L, -1)) <<
"include takes a filename.";
431 const std::string basename = lua_tostring(L, -1);
432 const std::string filename =
437 std::string error_msg =
438 "Tried to include " + filename +
439 " twice. Already included files in order of inclusion: ";
440 for (
const std::string& filename : parameter_dictionary->
included_files_) {
441 error_msg.append(filename);
442 error_msg.append(
"\n");
444 LOG(FATAL) << error_msg;
448 CHECK_EQ(lua_gettop(L), 0);
450 const std::string content =
451 parameter_dictionary->
file_resolver_->GetFileContentOrDie(basename);
453 L, luaL_loadbuffer(L, content.c_str(), content.size(), filename.c_str()));
454 CheckForLuaErrors(L, lua_pcall(L, 0, LUA_MULTRET, 0));
456 return lua_gettop(L);
461 CHECK_EQ(lua_gettop(L), 1);
462 CHECK(lua_isstring(L, -1)) <<
"read takes a filename.";
465 const std::string file_content =
467 lua_tostring(L, -1));
468 lua_pushstring(L, file_content.c_str());
std::string DoToString(const std::string &indent) const
std::string GetString(const std::string &key)
std::string PopString(Quoted quoted) const
std::vector< double > GetArrayValuesAsDoubles()
const std::shared_ptr< FileResolver > file_resolver_
LuaParameterDictionary(const std::string &code, std::unique_ptr< FileResolver > file_resolver)
std::vector< std::unique_ptr< LuaParameterDictionary > > GetArrayValuesAsDictionaries()
std::vector< std::string > GetArrayValuesAsStrings()
void CheckHasKey(const std::string &key) const
int GetNonNegativeInt(const std::string &key)
std::map< std::string, int > reference_counts_
std::string ToString() const
double GetDouble(const std::string &key)
void CheckAllKeysWereUsedExactlyOnceAndReset()
std::vector< std::string > GetKeys() const
int index_into_reference_table_
static int LuaInclude(lua_State *L)
static int LuaRead(lua_State *L)
const ReferenceCount reference_count_
static std::unique_ptr< LuaParameterDictionary > NonReferenceCounted(const std::string &code, std::unique_ptr< FileResolver > file_resolver)
std::vector< std::string > included_files_
std::unique_ptr< LuaParameterDictionary > PopDictionary(ReferenceCount reference_count) const
std::unique_ptr< LuaParameterDictionary > GetDictionary(const std::string &key)
void CheckHasKeyAndReference(const std::string &key)
bool GetBool(const std::string &key)
int GetInt(const std::string &key)
bool HasKey(const std::string &key) const
~LuaParameterDictionary()