feat: toml lvalues support
This commit is contained in:
parent
66825d62aa
commit
d14548cff8
@ -221,10 +221,6 @@ std::string_view BasicParser::readUntilEOL() {
|
||||
std::string BasicParser::parseName() {
|
||||
char c = peek();
|
||||
if (!is_identifier_start(c)) {
|
||||
if (c == '"') {
|
||||
pos++;
|
||||
return parseString(c);
|
||||
}
|
||||
throw error("identifier expected");
|
||||
}
|
||||
int start = pos;
|
||||
@ -234,6 +230,18 @@ std::string BasicParser::parseName() {
|
||||
return std::string(source.substr(start, pos - start));
|
||||
}
|
||||
|
||||
std::string BasicParser::parseXmlName() {
|
||||
char c = peek();
|
||||
if (!is_json_identifier_start(c)) {
|
||||
throw error("identifier expected");
|
||||
}
|
||||
int start = pos;
|
||||
while (hasNext() && is_json_identifier_part(source[pos])) {
|
||||
pos++;
|
||||
}
|
||||
return std::string(source.substr(start, pos - start));
|
||||
}
|
||||
|
||||
int64_t BasicParser::parseSimpleInt(int base) {
|
||||
char c = peek();
|
||||
int index = hexchar2int(c);
|
||||
|
||||
@ -30,14 +30,22 @@ inline bool is_whitespace(int c) {
|
||||
}
|
||||
|
||||
inline bool is_identifier_start(int c) {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' ||
|
||||
c == '.';
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
|
||||
}
|
||||
|
||||
inline bool is_identifier_part(int c) {
|
||||
return is_identifier_start(c) || is_digit(c) || c == '-';
|
||||
}
|
||||
|
||||
inline bool is_json_identifier_start(int c) {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' ||
|
||||
c == '.';
|
||||
}
|
||||
|
||||
inline bool is_json_identifier_part(int c) {
|
||||
return is_json_identifier_start(c) || is_digit(c) || c == '-';
|
||||
}
|
||||
|
||||
inline int hexchar2int(int c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
@ -99,6 +107,7 @@ public:
|
||||
std::string_view readUntil(char c);
|
||||
std::string_view readUntilEOL();
|
||||
std::string parseName();
|
||||
std::string parseXmlName();
|
||||
bool hasNext();
|
||||
char peek();
|
||||
char peekInLine();
|
||||
|
||||
@ -178,7 +178,8 @@ dv::value Parser::parseObject() {
|
||||
skipLine();
|
||||
continue;
|
||||
}
|
||||
std::string key = parseName();
|
||||
expect('"');
|
||||
std::string key = parseString('"');
|
||||
char next = peek();
|
||||
if (next != ':') {
|
||||
throw error("':' expected");
|
||||
|
||||
@ -26,32 +26,6 @@ class TomlReader : BasicParser {
|
||||
}
|
||||
}
|
||||
|
||||
dv::value& getSection(const std::string& section) {
|
||||
if (section.empty()) {
|
||||
return root;
|
||||
}
|
||||
size_t offset = 0;
|
||||
auto rootMap = &root;
|
||||
do {
|
||||
size_t index = section.find('.', offset);
|
||||
if (index == std::string::npos) {
|
||||
auto map = rootMap->at(section);
|
||||
if (!map) {
|
||||
return rootMap->object(section);
|
||||
}
|
||||
return *map;
|
||||
}
|
||||
auto subsection = section.substr(offset, index);
|
||||
auto map = rootMap->at(subsection);
|
||||
if (!map) {
|
||||
rootMap = &rootMap->object(subsection);
|
||||
} else {
|
||||
rootMap = &*map;
|
||||
}
|
||||
offset = index + 1;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
dv::value parseValue() {
|
||||
char c = peek();
|
||||
if (is_digit(c)) {
|
||||
@ -111,7 +85,30 @@ class TomlReader : BasicParser {
|
||||
}
|
||||
}
|
||||
|
||||
void readSection(const std::string& section, dv::value& map) {
|
||||
dv::value& parseLValue(dv::value& root) {
|
||||
dv::value* lvalue = &root;
|
||||
while (hasNext()) {
|
||||
char c = peek();
|
||||
std::string name;
|
||||
if (c == '\'' || c == '"') {
|
||||
pos++;
|
||||
name = parseString(c);
|
||||
} else {
|
||||
name = parseName();
|
||||
}
|
||||
if (lvalue->getType() == dv::value_type::none) {
|
||||
*lvalue = dv::object();
|
||||
}
|
||||
lvalue = &(*lvalue)[name];
|
||||
if (peek() != '.') {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return *lvalue;
|
||||
}
|
||||
|
||||
void readSection(dv::value& map, dv::value& root) {
|
||||
while (hasNext()) {
|
||||
skipWhitespace();
|
||||
if (!hasNext()) {
|
||||
@ -119,15 +116,15 @@ class TomlReader : BasicParser {
|
||||
}
|
||||
char c = nextChar();
|
||||
if (c == '[') {
|
||||
std::string name = parseName();
|
||||
pos++;
|
||||
readSection(name, getSection(name));
|
||||
dv::value& section = parseLValue(root);
|
||||
expect(']');
|
||||
readSection(section, root);
|
||||
return;
|
||||
}
|
||||
pos--;
|
||||
std::string name = parseName();
|
||||
dv::value& lvalue = parseLValue(map);
|
||||
expect('=');
|
||||
map[name] = parseValue();
|
||||
lvalue = parseValue();
|
||||
expectNewLine();
|
||||
}
|
||||
}
|
||||
@ -141,7 +138,7 @@ public:
|
||||
if (!hasNext()) {
|
||||
return std::move(root);
|
||||
}
|
||||
readSection("", root);
|
||||
readSection(root, root);
|
||||
return std::move(root);
|
||||
}
|
||||
};
|
||||
@ -150,6 +147,7 @@ void toml::parse(
|
||||
SettingsHandler& handler, std::string_view file, std::string_view source
|
||||
) {
|
||||
auto map = parse(file, source);
|
||||
|
||||
for (const auto& [sectionName, sectionMap] : map.asObject()) {
|
||||
if (!sectionMap.isObject()) {
|
||||
continue;
|
||||
|
||||
@ -157,5 +157,5 @@ namespace dv {
|
||||
#include "coders/json.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const dv::value& value) {
|
||||
return stream << json::stringify(value, false);
|
||||
return stream << json::stringify(value, true);
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "coders/imageio.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentBuilder.hpp"
|
||||
#include "content/ContentLoader.hpp"
|
||||
@ -125,7 +126,12 @@ void Engine::loadSettings() {
|
||||
if (fs::is_regular_file(settings_file)) {
|
||||
logger.info() << "loading settings";
|
||||
std::string text = files::read_string(settings_file);
|
||||
toml::parse(settingsHandler, settings_file.string(), text);
|
||||
try {
|
||||
toml::parse(settingsHandler, settings_file.string(), text);
|
||||
} catch (const parsing_error& err) {
|
||||
logger.error() << err.errorLog();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -196,22 +196,25 @@ void Events::loadBindings(
|
||||
const std::string& filename, const std::string& source
|
||||
) {
|
||||
auto map = toml::parse(filename, source);
|
||||
for (auto& [key, value] : map.asObject()) {
|
||||
auto [prefix, codename] = util::split_at(value.asString(), ':');
|
||||
inputtype type;
|
||||
int code;
|
||||
if (prefix == "key") {
|
||||
type = inputtype::keyboard;
|
||||
code = static_cast<int>(input_util::keycode_from(codename));
|
||||
} else if (prefix == "mouse") {
|
||||
type = inputtype::mouse;
|
||||
code = static_cast<int>(input_util::mousecode_from(codename));
|
||||
} else {
|
||||
logger.error()
|
||||
<< "unknown input type: " << prefix << " (binding "
|
||||
<< util::quote(key) << ")";
|
||||
continue;
|
||||
for (auto& [sectionName, section] : map.asObject()) {
|
||||
for (auto& [name, value] : section.asObject()) {
|
||||
auto key = sectionName + "." + name;
|
||||
auto [prefix, codename] = util::split_at(value.asString(), ':');
|
||||
inputtype type;
|
||||
int code;
|
||||
if (prefix == "key") {
|
||||
type = inputtype::keyboard;
|
||||
code = static_cast<int>(input_util::keycode_from(codename));
|
||||
} else if (prefix == "mouse") {
|
||||
type = inputtype::mouse;
|
||||
code = static_cast<int>(input_util::mousecode_from(codename));
|
||||
} else {
|
||||
logger.error()
|
||||
<< "unknown input type: " << prefix << " (binding "
|
||||
<< util::quote(key) << ")";
|
||||
continue;
|
||||
}
|
||||
Events::bind(key, type, code);
|
||||
}
|
||||
Events::bind(key, type, code);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user