feat: toml arrays and inline tables support
This commit is contained in:
parent
b984e363ea
commit
66825d62aa
@ -52,6 +52,65 @@ class TomlReader : BasicParser {
|
||||
} while (true);
|
||||
}
|
||||
|
||||
dv::value parseValue() {
|
||||
char c = peek();
|
||||
if (is_digit(c)) {
|
||||
return parseNumber(1);
|
||||
} else if (c == '-' || c == '+') {
|
||||
int sign = c == '-' ? -1 : 1;
|
||||
pos++;
|
||||
// parse numeric literal
|
||||
auto value = parseNumber(sign);
|
||||
if (hasNext() && peekNoJump() == '-') {
|
||||
// parse timestamp // TODO: implement
|
||||
throw error("timestamps support is not implemented yet");
|
||||
}
|
||||
return value;
|
||||
} else if (is_identifier_start(c)) {
|
||||
// parse keywords
|
||||
std::string keyword = parseName();
|
||||
if (keyword == "true" || keyword == "false") {
|
||||
return keyword == "true";
|
||||
} else if (keyword == "inf") {
|
||||
return INFINITY;
|
||||
} else if (keyword == "nan") {
|
||||
return NAN;
|
||||
}
|
||||
throw error("unknown keyword " + util::quote(keyword));
|
||||
} else if (c == '"' || c == '\'') {
|
||||
pos++;
|
||||
return parseString(c);
|
||||
} else if (c == '[') {
|
||||
// parse array
|
||||
pos++;
|
||||
dv::list_t values;
|
||||
while (peek() != ']') {
|
||||
values.push_back(parseValue());
|
||||
if (peek() != ']') {
|
||||
expect(',');
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
return dv::value(std::move(values));
|
||||
} else if (c == '{') {
|
||||
// parse inline table
|
||||
pos++;
|
||||
auto table = dv::object();
|
||||
while (peek() != '}') {
|
||||
auto key = parseName();
|
||||
expect('=');
|
||||
table[key] = parseValue();
|
||||
if (peek() != '}') {
|
||||
expect(',');
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
return table;
|
||||
} else {
|
||||
throw error("feature is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
void readSection(const std::string& section, dv::value& map) {
|
||||
while (hasNext()) {
|
||||
skipWhitespace();
|
||||
@ -68,35 +127,13 @@ class TomlReader : BasicParser {
|
||||
pos--;
|
||||
std::string name = parseName();
|
||||
expect('=');
|
||||
c = peek();
|
||||
if (is_digit(c)) {
|
||||
map[name] = parseNumber(1);
|
||||
} else if (c == '-' || c == '+') {
|
||||
int sign = c == '-' ? -1 : 1;
|
||||
pos++;
|
||||
map[name] = parseNumber(sign);
|
||||
} else if (is_identifier_start(c)) {
|
||||
std::string identifier = parseName();
|
||||
if (identifier == "true" || identifier == "false") {
|
||||
map[name] = identifier == "true";
|
||||
} else if (identifier == "inf") {
|
||||
map[name] = INFINITY;
|
||||
} else if (identifier == "nan") {
|
||||
map[name] = NAN;
|
||||
}
|
||||
} else if (c == '"' || c == '\'') {
|
||||
pos++;
|
||||
map[name] = parseString(c);
|
||||
} else {
|
||||
throw error("feature is not supported");
|
||||
}
|
||||
map[name] = parseValue();
|
||||
expectNewLine();
|
||||
}
|
||||
}
|
||||
public:
|
||||
TomlReader(std::string_view file, std::string_view source)
|
||||
: BasicParser(file, source) {
|
||||
root = dv::object();
|
||||
: BasicParser(file, source), root(dv::object()) {
|
||||
}
|
||||
|
||||
dv::value read() {
|
||||
|
||||
@ -196,6 +196,9 @@ namespace dv {
|
||||
value(std::shared_ptr<objects::Bytes> v) noexcept {
|
||||
this->operator=(std::move(v));
|
||||
}
|
||||
value(list_t values) {
|
||||
this->operator=(std::make_shared<list_t>(std::move(values)));
|
||||
}
|
||||
|
||||
value(const value& v) noexcept : type(value_type::none) {
|
||||
this->operator=(v);
|
||||
|
||||
86
test/coders/toml.cpp
Normal file
86
test/coders/toml.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "coders/toml.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "data/dv.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "util/Buffer.hpp"
|
||||
#include "coders/commons.hpp"
|
||||
|
||||
// Example from toml.io
|
||||
inline std::string SRC_EXAMPLE =
|
||||
"# This is a TOML document\n"
|
||||
"\n"
|
||||
"title = \"TOML Example\"\n"
|
||||
"\n"
|
||||
"[owner]\n"
|
||||
"name = \"Tom Preston-Werner\"\n"
|
||||
// "dob = 1979-05-27T07:32:00-08:00\n"
|
||||
"\n"
|
||||
"[database]\n"
|
||||
"enabled = true\n"
|
||||
"ports = [ 8000, 8001, 8002 ]\n"
|
||||
"data = [ [\"delta\", \"phi\"], [3.14] ]\n"
|
||||
"temp_targets = { cpu = 79.5, case = 72.0 }\n"
|
||||
"\n"
|
||||
"[servers]\n"
|
||||
"\n"
|
||||
"[servers.alpha]\n"
|
||||
"ip = \"10.0.0.1\"\n"
|
||||
"role = \"frontend\"\n"
|
||||
"\n"
|
||||
"[servers.beta]\n"
|
||||
"ip = \"10.0.0.2\"\n"
|
||||
"role = \"backend\"";
|
||||
|
||||
TEST(TOML, EncodeDecode) {
|
||||
const std::string name = "TOML-encoder";
|
||||
const int bytesSize = 20;
|
||||
const int year = 2019;
|
||||
const float score = 3.141592;
|
||||
const bool visible = true;
|
||||
dv::objects::Bytes srcBytes(bytesSize);
|
||||
for (int i = 0; i < bytesSize; i ++) {
|
||||
srcBytes[i] = rand();
|
||||
}
|
||||
|
||||
std::string text;
|
||||
{
|
||||
auto object = dv::object();
|
||||
object["name"] = name;
|
||||
object["year"] = year;
|
||||
object["score"] = score;
|
||||
object["visible"] = visible;
|
||||
object["data"] = srcBytes;
|
||||
|
||||
text = toml::stringify(object, "");
|
||||
std::cout << text << std::endl;
|
||||
}
|
||||
try {
|
||||
auto object = toml::parse("<string>", text);
|
||||
EXPECT_EQ(object["name"].asString(), name);
|
||||
EXPECT_EQ(object["year"].asInteger(), year);
|
||||
EXPECT_FLOAT_EQ(object["score"].asNumber(), score);
|
||||
EXPECT_EQ(object["visible"].asBoolean(), visible);
|
||||
auto b64string = object["data"].asString();
|
||||
|
||||
auto bytes = util::base64_decode(b64string);
|
||||
EXPECT_EQ(bytes.size(), bytesSize);
|
||||
for (int i = 0; i < bytesSize; i++) {
|
||||
EXPECT_EQ(bytes[i], srcBytes[i]);
|
||||
}
|
||||
} catch (const parsing_error& err) {
|
||||
std::cerr << err.errorLog() << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TOML, ExampleCode) {
|
||||
try {
|
||||
auto object = toml::parse("<string>", SRC_EXAMPLE);
|
||||
std::cout << object << std::endl;
|
||||
} catch (const parsing_error& err) {
|
||||
std::cerr << err.errorLog() << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user