mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4aecc8e4b | ||
|
|
60c81d06a0 | ||
|
|
46569da231 | ||
|
|
5e20a8ff16 | ||
|
|
dd9319245e | ||
|
|
53f6b8268b | ||
|
|
32dcc35918 | ||
|
|
8c3854b28b | ||
|
|
75af9c79df | ||
|
|
1dfe32acd8 | ||
|
|
5dfdbe4bff | ||
|
|
4584eeb57a | ||
|
|
aa67069387 | ||
|
|
ee3424ad51 | ||
|
|
17def14ab6 | ||
|
|
b5b8830c29 | ||
|
|
87a5c844c2 | ||
|
|
11c7ee4501 | ||
|
|
d24a188d4c | ||
|
|
29876221f8 | ||
|
|
7c03c446fe |
15
README.md
15
README.md
@@ -3,10 +3,11 @@ toml11
|
|||||||
|
|
||||||
[](https://travis-ci.org/ToruNiina/toml11)
|
[](https://travis-ci.org/ToruNiina/toml11)
|
||||||
[](https://ci.appveyor.com/project/ToruNiina/toml11)
|
[](https://ci.appveyor.com/project/ToruNiina/toml11)
|
||||||
[](LICENSE)
|
[](https://github.com/ToruNiina/toml11/releases)
|
||||||
|
[](LICENSE)
|
||||||
[](https://doi.org/10.5281/zenodo.1209136)
|
[](https://doi.org/10.5281/zenodo.1209136)
|
||||||
|
|
||||||
c++11 header-only toml parser depending only on c++ standard library.
|
C++11 header-only toml parser depending only on C++ standard library.
|
||||||
|
|
||||||
compatible to the latest version of [TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md) after version 2.0.0.
|
compatible to the latest version of [TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md) after version 2.0.0.
|
||||||
|
|
||||||
@@ -42,8 +43,14 @@ In the case of file open error, it will throw `std::runtime_error`.
|
|||||||
|
|
||||||
You can also pass a `stream` to the `toml::parse` function after checking the status.
|
You can also pass a `stream` to the `toml::parse` function after checking the status.
|
||||||
|
|
||||||
|
Note that on __Windows OS__, stream that is opened as text-mode automatically converts
|
||||||
|
CRLF ("\r\n") into LF ("\n") and this leads inconsistency between file size and
|
||||||
|
the contents that would be read. This causes weird error. To use a file stream
|
||||||
|
with `toml::parse`, don't forget to pass binary mode flag when you open the
|
||||||
|
stream.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::ifstream ifs("sample.toml");
|
std::ifstream ifs("sample.toml", std::ios_base::binary);
|
||||||
assert(ifs.good());
|
assert(ifs.good());
|
||||||
const auto data = toml::parse(ifs /*, "filename" (optional)*/);
|
const auto data = toml::parse(ifs /*, "filename" (optional)*/);
|
||||||
```
|
```
|
||||||
@@ -485,6 +492,8 @@ I thank the contributor for providing great feature to this repository.
|
|||||||
- Guillaume Fraux (@Luthaf)
|
- Guillaume Fraux (@Luthaf)
|
||||||
- Windows support and CI on Appvayor
|
- Windows support and CI on Appvayor
|
||||||
- Intel Compiler support
|
- Intel Compiler support
|
||||||
|
- Quentin Khan (@xaxousis)
|
||||||
|
- Found & Fixed a bug around ODR
|
||||||
|
|
||||||
## Licensing terms
|
## Licensing terms
|
||||||
|
|
||||||
|
|||||||
@@ -194,3 +194,504 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
|
|||||||
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
|
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
|
||||||
expected_multi_line_array);
|
expected_multi_line_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// after here, the test codes generate the content of a file.
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_file_with_BOM)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"\xEF\xBB\xBF" // BOM
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss, "test_file_with_BOM.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"\xEF\xBB\xBF" // BOM
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
);
|
||||||
|
{
|
||||||
|
std::ofstream ofs("tmp.toml");
|
||||||
|
ofs << table;
|
||||||
|
}
|
||||||
|
const auto data = toml::parse("tmp.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"\xEF\xBB\xBF" // BOM
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss, "test_file_with_BOM_CRLF.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"\xEF\xBB\xBF" // BOM
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
);
|
||||||
|
{
|
||||||
|
// with text-mode, "\n" is converted to "\r\n" and the resulting
|
||||||
|
// value will be "\r\r\n". To avoid the additional "\r", use binary
|
||||||
|
// mode.
|
||||||
|
std::ofstream ofs("tmp.toml", std::ios_base::binary);
|
||||||
|
ofs.write(table.data(), table.size());
|
||||||
|
}
|
||||||
|
const auto data = toml::parse("tmp.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\""
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_file_without_newline_at_the_end_of_file.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\""
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_file_without_newline_at_the_end_of_file_CRLF.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\" # comment"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_file_without_newline_at_the_end_of_file_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\" # comment"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_file_without_newline_at_the_end_of_file_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\" \t"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_file_without_newline_at_the_end_of_file_ws.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\" \t"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_file_without_newline_at_the_end_of_file_ws.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
|
||||||
|
{
|
||||||
|
// comment w/o newline
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"# comment"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"# comment\n"
|
||||||
|
"# one more comment"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// comment w/ newline
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"# comment\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"# comment\n"
|
||||||
|
"# one more comment\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRLF version
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"# comment"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"# comment\r\n"
|
||||||
|
"# one more comment"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"# comment\r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"# comment\r\n"
|
||||||
|
"# one more comment\r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_comment.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// with whitespaces
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
" \n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
" \n"
|
||||||
|
" \n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"\n"
|
||||||
|
" \n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
" \n"
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// with whitespaces but no newline
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\n"
|
||||||
|
"[table]\n"
|
||||||
|
"key = \"value\"\n"
|
||||||
|
" "
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CRLF
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
// with whitespaces
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
" \r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
" \r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
" \r\n"
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
" \r\n"
|
||||||
|
" \r\n"
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const std::string table(
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
"[table]\r\n"
|
||||||
|
"key = \"value\"\r\n"
|
||||||
|
" "
|
||||||
|
);
|
||||||
|
std::istringstream iss(table);
|
||||||
|
const auto data = toml::parse(iss,
|
||||||
|
"test_files_end_with_newline.toml");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
|
||||||
|
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
12
toml/get.hpp
12
toml/get.hpp
@@ -295,7 +295,7 @@ T get(const toml::value& v)
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// find and get
|
// find and get
|
||||||
|
|
||||||
template<typename T>
|
template<typename T = ::toml::value>
|
||||||
decltype(::toml::get<T>(std::declval<const ::toml::value&>()))
|
decltype(::toml::get<T>(std::declval<const ::toml::value&>()))
|
||||||
find(const toml::table& tab, const toml::key& ky,
|
find(const toml::table& tab, const toml::key& ky,
|
||||||
std::string tablename = "unknown table")
|
std::string tablename = "unknown table")
|
||||||
@@ -307,7 +307,7 @@ find(const toml::table& tab, const toml::key& ky,
|
|||||||
}
|
}
|
||||||
return ::toml::get<T>(tab.at(ky));
|
return ::toml::get<T>(tab.at(ky));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T = ::toml::value>
|
||||||
decltype(::toml::get<T>(std::declval<::toml::value&>()))
|
decltype(::toml::get<T>(std::declval<::toml::value&>()))
|
||||||
find(toml::table& tab, const toml::key& ky,
|
find(toml::table& tab, const toml::key& ky,
|
||||||
std::string tablename = "unknown table")
|
std::string tablename = "unknown table")
|
||||||
@@ -319,7 +319,7 @@ find(toml::table& tab, const toml::key& ky,
|
|||||||
}
|
}
|
||||||
return ::toml::get<T>(tab[ky]);
|
return ::toml::get<T>(tab[ky]);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T = ::toml::value>
|
||||||
decltype(::toml::get<T>(std::declval<::toml::value&&>()))
|
decltype(::toml::get<T>(std::declval<::toml::value&&>()))
|
||||||
find(toml::table&& tab, const toml::key& ky,
|
find(toml::table&& tab, const toml::key& ky,
|
||||||
std::string tablename = "unknown table")
|
std::string tablename = "unknown table")
|
||||||
@@ -332,7 +332,7 @@ find(toml::table&& tab, const toml::key& ky,
|
|||||||
return ::toml::get<T>(std::move(tab[ky]));
|
return ::toml::get<T>(std::move(tab[ky]));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T = ::toml::value>
|
||||||
decltype(::toml::get<T>(std::declval<const ::toml::value&>()))
|
decltype(::toml::get<T>(std::declval<const ::toml::value&>()))
|
||||||
find(const toml::value& v, const toml::key& ky)
|
find(const toml::value& v, const toml::key& ky)
|
||||||
{
|
{
|
||||||
@@ -345,7 +345,7 @@ find(const toml::value& v, const toml::key& ky)
|
|||||||
}
|
}
|
||||||
return ::toml::get<T>(tab.at(ky));
|
return ::toml::get<T>(tab.at(ky));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T = ::toml::value>
|
||||||
decltype(::toml::get<T>(std::declval<::toml::value&>()))
|
decltype(::toml::get<T>(std::declval<::toml::value&>()))
|
||||||
find(toml::value& v, const toml::key& ky)
|
find(toml::value& v, const toml::key& ky)
|
||||||
{
|
{
|
||||||
@@ -358,7 +358,7 @@ find(toml::value& v, const toml::key& ky)
|
|||||||
}
|
}
|
||||||
return ::toml::get<T>(tab.at(ky));
|
return ::toml::get<T>(tab.at(ky));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T = ::toml::value>
|
||||||
decltype(::toml::get<T>(std::declval<::toml::value&&>()))
|
decltype(::toml::get<T>(std::declval<::toml::value&&>()))
|
||||||
find(toml::value&& v, const toml::key& ky)
|
find(toml::value&& v, const toml::key& ky)
|
||||||
{
|
{
|
||||||
|
|||||||
117
toml/parser.hpp
117
toml/parser.hpp
@@ -34,8 +34,8 @@ parse_boolean(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loc.iter() = first; //rollback
|
loc.iter() = first; //rollback
|
||||||
return err(format_underline("[error] toml::parse_boolean", loc,
|
return err(std::string("[error] toml::parse_boolean: "
|
||||||
"token is not boolean", {"boolean is `true` or `false`"}));
|
"the next token is not a boolean"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -63,8 +63,8 @@ parse_binary_integer(location<Container>& loc)
|
|||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(format_underline("[error] toml::parse_binary_integer", loc,
|
return err(std::string("[error] toml::parse_binary_integer:"
|
||||||
"token is not binary integer", {"binary integer is like: 0b0011"}));
|
"the next token is not an integer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -84,9 +84,8 @@ parse_octal_integer(location<Container>& loc)
|
|||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
|
return err(std::string("[error] toml::parse_octal_integer:"
|
||||||
return err(format_underline("[error] toml::parse_octal_integer", loc,
|
"the next token is not an integer"));
|
||||||
"token is not octal integer", {"octal integer is like: 0o775"}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -106,8 +105,8 @@ parse_hexadecimal_integer(location<Container>& loc)
|
|||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(format_underline("[error] toml::parse_hexadecimal_integer", loc,
|
return err(std::string("[error] toml::parse_hexadecimal_integer"
|
||||||
"token is not hex integer", {"hex integer is like: 0xC0FFEE"}));
|
"the next token is not an integer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -134,10 +133,8 @@ parse_integer(location<Container>& loc)
|
|||||||
return ok(std::make_pair(retval, token.unwrap()));
|
return ok(std::make_pair(retval, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(format_underline("[error] toml::parse_integer", loc,
|
return err(std::string("[error] toml::parse_integer: "
|
||||||
"token is not integer", {"integer is like: +42",
|
"the next token is not an integer"));
|
||||||
"hex integer is like: 0xC0FFEE", "octal integer is like: 0o775",
|
|
||||||
"binary integer is like: 0b0011"}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -225,8 +222,8 @@ parse_floating(location<Container>& loc)
|
|||||||
return ok(std::make_pair(v, token.unwrap()));
|
return ok(std::make_pair(v, token.unwrap()));
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(format_underline("[error] toml::parse_floating: ", loc,
|
return err(std::string("[error] toml::parse_floating: "
|
||||||
"token is not a float", {"floating point is like: -3.14e+1"}));
|
"the next token is not a float"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -286,9 +283,8 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
|||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
if(first == loc.end() || *first != '\\')
|
if(first == loc.end() || *first != '\\')
|
||||||
{
|
{
|
||||||
return err(format_underline("[error]: "
|
return err(std::string("[error]: toml::parse_escape_sequence: "
|
||||||
"toml::parse_escape_sequence: location does not points \"\\\"",
|
"the next token is not an escape sequence \"\\\""));
|
||||||
loc, "should be \"\\\""));
|
|
||||||
}
|
}
|
||||||
++loc.iter();
|
++loc.iter();
|
||||||
switch(*loc.iter())
|
switch(*loc.iter())
|
||||||
@@ -527,8 +523,8 @@ parse_string(location<Container>& loc)
|
|||||||
if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;}
|
if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;}
|
||||||
if(const auto rslt = parse_basic_string(loc)) {return rslt;}
|
if(const auto rslt = parse_basic_string(loc)) {return rslt;}
|
||||||
if(const auto rslt = parse_literal_string(loc)) {return rslt;}
|
if(const auto rslt = parse_literal_string(loc)) {return rslt;}
|
||||||
return err(format_underline("[error] toml::parse_string: not a string",
|
return err(std::string("[error] toml::parse_string: "
|
||||||
loc, "not a string"));
|
"the next token is not a string"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
@@ -576,11 +572,9 @@ parse_local_date(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto msg = format_underline("[error]: toml::parse_local_date: "
|
|
||||||
"invalid format", loc, token.unwrap_err(),
|
|
||||||
{"local date is like: 1979-05-27"});
|
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(std::move(msg));
|
return err(std::string("[error]: toml::parse_local_date: "
|
||||||
|
"the next token is not a local_date"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,11 +655,9 @@ parse_local_time(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto msg = format_underline("[error]: toml::parse_local_time: "
|
|
||||||
"invalid format", loc, token.unwrap_err(),
|
|
||||||
{"local time is like: 00:32:00.999999"});
|
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(std::move(msg));
|
return err(std::string("[error]: toml::parse_local_time: "
|
||||||
|
"the next token is not a local_time"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,11 +698,9 @@ parse_local_datetime(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto msg = format_underline("[error]: toml::parse_local_datetime: "
|
|
||||||
"invalid format", loc, token.unwrap_err(),
|
|
||||||
{"local datetime is like: 1979-05-27T00:32:00.999999"});
|
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(std::move(msg));
|
return err(std::string("[error]: toml::parse_local_datetime: "
|
||||||
|
"the next token is not a local_datetime"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,12 +747,9 @@ parse_offset_datetime(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto msg = format_underline("[error]: toml::parse_offset_datetime: "
|
|
||||||
"invalid format", loc, token.unwrap_err(),
|
|
||||||
{"offset datetime is like: 1979-05-27T00:32:00-07:00",
|
|
||||||
"or in UTC (w/o offset) : 1979-05-27T00:32:00Z"});
|
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(std::move(msg));
|
return err(std::string("[error]: toml::parse_offset_datetime: "
|
||||||
|
"the next token is not a local_datetime"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,8 +768,8 @@ result<key, std::string> parse_simple_key(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
return ok(bare.unwrap().str());
|
return ok(bare.unwrap().str());
|
||||||
}
|
}
|
||||||
return err(format_underline("[error] toml::parse_simple_key: "
|
return err(std::string("[error] toml::parse_simple_key: "
|
||||||
"the next token is not a simple key", loc, "not a key"));
|
"the next token is not a simple key"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// dotted key become vector of keys
|
// dotted key become vector of keys
|
||||||
@@ -835,8 +822,8 @@ result<std::vector<key>, std::string> parse_key(location<Container>& loc)
|
|||||||
{
|
{
|
||||||
return ok(std::vector<key>(1, smpl.unwrap()));
|
return ok(std::vector<key>(1, smpl.unwrap()));
|
||||||
}
|
}
|
||||||
return err(format_underline("toml::parse_key: the next token is not a key",
|
return err(std::string("[error] toml::parse_key: "
|
||||||
loc, "not a key"));
|
"the next token is not a key"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward-decl to implement parse_array and parse_table
|
// forward-decl to implement parse_array and parse_table
|
||||||
@@ -854,8 +841,7 @@ parse_array(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
if(*loc.iter() != '[')
|
if(*loc.iter() != '[')
|
||||||
{
|
{
|
||||||
return err(format_underline("[error] toml::parse_array: "
|
return err("[error] toml::parse_array: token is not an array");
|
||||||
"token is not an array", loc, "should be ["));
|
|
||||||
}
|
}
|
||||||
++loc.iter();
|
++loc.iter();
|
||||||
|
|
||||||
@@ -903,13 +889,13 @@ parse_array(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return err(format_underline("[error] toml::parse_array: "
|
throw syntax_error(format_underline("[error] toml::parse_array:"
|
||||||
" missing array separator `,`", loc, "should be `,`"));
|
" missing array separator `,`", loc, "should be `,`"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(format_underline("[error] toml::parse_array: "
|
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||||
"array did not closed by `]`", loc, "should be closed"));
|
"array did not closed by `]`", loc, "should be closed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1181,10 +1167,11 @@ parse_inline_table(location<Container>& loc)
|
|||||||
table retval;
|
table retval;
|
||||||
if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
|
if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
|
||||||
{
|
{
|
||||||
return err(format_underline("[error] toml::parse_inline_table: "
|
return err(std::string("[error] toml::parse_inline_table: "
|
||||||
"the next token is not an inline table", loc, "not `{`."));
|
"the next token is not an inline table"));
|
||||||
}
|
}
|
||||||
++loc.iter();
|
++loc.iter();
|
||||||
|
// it starts from "{". it should be formatted as inline-table
|
||||||
while(loc.iter() != loc.end())
|
while(loc.iter() != loc.end())
|
||||||
{
|
{
|
||||||
maybe<lex_ws>::invoke(loc);
|
maybe<lex_ws>::invoke(loc);
|
||||||
@@ -1224,13 +1211,14 @@ parse_inline_table(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return err(format_underline("[error] toml:::parse_inline_table:"
|
throw syntax_error(format_underline("[error] "
|
||||||
" missing table separator `,` ", loc, "should be `,`"));
|
"toml:::parse_inline_table: missing table separator `,` ",
|
||||||
|
loc, "should be `,`"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(format_underline("[error] toml::parse_inline_table: "
|
throw syntax_error(format_underline("[error] toml::parse_inline_table: "
|
||||||
"inline table did not closed by `}`", loc, "should be closed"));
|
"inline table did not closed by `}`", loc, "should be closed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1357,7 +1345,7 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
|||||||
return err(std::string("toml::parse_ml_table: input is empty"));
|
return err(std::string("toml::parse_ml_table: input is empty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX at lest one newline is needed
|
// XXX at lest one newline is needed.
|
||||||
using skip_line = repeat<
|
using skip_line = repeat<
|
||||||
sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>;
|
sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>;
|
||||||
skip_line::invoke(loc);
|
skip_line::invoke(loc);
|
||||||
@@ -1377,6 +1365,7 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
|||||||
loc.iter() = before;
|
loc.iter() = before;
|
||||||
return ok(tab);
|
return ok(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(const auto kv = parse_key_value_pair(loc))
|
if(const auto kv = parse_key_value_pair(loc))
|
||||||
{
|
{
|
||||||
const std::vector<key>& keys = kv.unwrap().first;
|
const std::vector<key>& keys = kv.unwrap().first;
|
||||||
@@ -1393,6 +1382,17 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
|||||||
return err(kv.unwrap_err());
|
return err(kv.unwrap_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// comment lines are skipped by the above function call.
|
||||||
|
// However, since the `skip_line` requires at least 1 newline, it fails
|
||||||
|
// if the file ends with ws and/or comment without newline.
|
||||||
|
// `skip_line` matches `ws? + comment? + newline`, not `ws` or `comment`
|
||||||
|
// itself. To skip the last ws and/or comment, call lexers.
|
||||||
|
// It does not matter if these fails, so the return value is discarded.
|
||||||
|
lex_ws::invoke(loc);
|
||||||
|
lex_comment::invoke(loc);
|
||||||
|
|
||||||
|
// skip_line is (whitespace? comment? newline)_{1,}. multiple empty lines
|
||||||
|
// and comments after the last key-value pairs are allowed.
|
||||||
const auto newline = skip_line::invoke(loc);
|
const auto newline = skip_line::invoke(loc);
|
||||||
if(!newline && loc.iter() != loc.end())
|
if(!newline && loc.iter() != loc.end())
|
||||||
{
|
{
|
||||||
@@ -1405,11 +1405,10 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
|||||||
return err(msg);
|
return err(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// comment lines are skipped by the above function call.
|
// the skip_lines only matches with lines that includes newline.
|
||||||
// However, if the file ends with comment without newline,
|
// to skip the last line that includes comment and/or whitespace
|
||||||
// it might cause parsing error because skip_line matches
|
// but no newline, call them one more time.
|
||||||
// `comment + newline`, not `comment` itself. to skip the
|
lex_ws::invoke(loc);
|
||||||
// last comment, call lex_comment one more time.
|
|
||||||
lex_comment::invoke(loc);
|
lex_comment::invoke(loc);
|
||||||
}
|
}
|
||||||
return ok(tab);
|
return ok(tab);
|
||||||
@@ -1498,10 +1497,10 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
|
|||||||
// be compared to char. However, since we are always out of luck, we need to
|
// be compared to char. However, since we are always out of luck, we need to
|
||||||
// check our chars are equivalent to BOM. To do this, first we need to
|
// check our chars are equivalent to BOM. To do this, first we need to
|
||||||
// convert char to unsigned char to guarantee the comparability.
|
// convert char to unsigned char to guarantee the comparability.
|
||||||
if(letters.size() >= 3)
|
if(loc.source()->size() >= 3)
|
||||||
{
|
{
|
||||||
std::array<unsigned char, 3> BOM;
|
std::array<unsigned char, 3> BOM;
|
||||||
std::memcpy(BOM.data(), letters.data(), 3);
|
std::memcpy(BOM.data(), loc.source()->data(), 3);
|
||||||
if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
|
if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
|
||||||
{
|
{
|
||||||
loc.iter() += 3; // BOM found. skip.
|
loc.iter() += 3; // BOM found. skip.
|
||||||
@@ -1518,7 +1517,7 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
|
|||||||
|
|
||||||
inline table parse(const std::string& fname)
|
inline table parse(const std::string& fname)
|
||||||
{
|
{
|
||||||
std::ifstream ifs(fname.c_str());
|
std::ifstream ifs(fname.c_str(), std::ios_base::binary);
|
||||||
if(!ifs.good())
|
if(!ifs.good())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("toml::parse: file open error -> " + fname);
|
throw std::runtime_error("toml::parse: file open error -> " + fname);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Distributed under the MIT License.
|
// Distributed under the MIT License.
|
||||||
#ifndef TOML11_RESULT_H
|
#ifndef TOML11_RESULT_H
|
||||||
#define TOML11_RESULT_H
|
#define TOML11_RESULT_H
|
||||||
|
#include "traits.hpp"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -13,19 +14,6 @@
|
|||||||
namespace toml
|
namespace toml
|
||||||
{
|
{
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
|
|
||||||
template<typename F, typename ... Args>
|
|
||||||
using return_type_of_t = std::invoke_result_t<F, Args...>;
|
|
||||||
|
|
||||||
#else
|
|
||||||
// result_of is deprecated after C++17
|
|
||||||
template<typename F, typename ... Args>
|
|
||||||
using return_type_of_t = typename std::result_of<F(Args...)>::type;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct success
|
struct success
|
||||||
{
|
{
|
||||||
@@ -441,21 +429,21 @@ struct result
|
|||||||
// F: T -> U
|
// F: T -> U
|
||||||
// retval: result<U, E>
|
// retval: result<U, E>
|
||||||
template<typename F>
|
template<typename F>
|
||||||
result<return_type_of_t<F, value_type&>, error_type>
|
result<detail::return_type_of_t<F, value_type&>, error_type>
|
||||||
map(F&& f) &
|
map(F&& f) &
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return ok(f(this->as_ok()));}
|
if(this->is_ok()){return ok(f(this->as_ok()));}
|
||||||
return err(this->as_err());
|
return err(this->as_err());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
result<return_type_of_t<F, value_type const&>, error_type>
|
result<detail::return_type_of_t<F, value_type const&>, error_type>
|
||||||
map(F&& f) const&
|
map(F&& f) const&
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return ok(f(this->as_ok()));}
|
if(this->is_ok()){return ok(f(this->as_ok()));}
|
||||||
return err(this->as_err());
|
return err(this->as_err());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
result<return_type_of_t<F, value_type &&>, error_type>
|
result<detail::return_type_of_t<F, value_type &&>, error_type>
|
||||||
map(F&& f) &&
|
map(F&& f) &&
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return ok(f(std::move(this->as_ok())));}
|
if(this->is_ok()){return ok(f(std::move(this->as_ok())));}
|
||||||
@@ -466,21 +454,21 @@ struct result
|
|||||||
// F: E -> F
|
// F: E -> F
|
||||||
// retval: result<T, F>
|
// retval: result<T, F>
|
||||||
template<typename F>
|
template<typename F>
|
||||||
result<value_type, return_type_of_t<F, error_type&>>
|
result<value_type, detail::return_type_of_t<F, error_type&>>
|
||||||
map_err(F&& f) &
|
map_err(F&& f) &
|
||||||
{
|
{
|
||||||
if(this->is_err()){return err(f(this->as_err()));}
|
if(this->is_err()){return err(f(this->as_err()));}
|
||||||
return ok(this->as_ok());
|
return ok(this->as_ok());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
result<value_type, return_type_of_t<F, error_type const&>>
|
result<value_type, detail::return_type_of_t<F, error_type const&>>
|
||||||
map_err(F&& f) const&
|
map_err(F&& f) const&
|
||||||
{
|
{
|
||||||
if(this->is_err()){return err(f(this->as_err()));}
|
if(this->is_err()){return err(f(this->as_err()));}
|
||||||
return ok(this->as_ok());
|
return ok(this->as_ok());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
result<value_type, return_type_of_t<F, error_type&&>>
|
result<value_type, detail::return_type_of_t<F, error_type&&>>
|
||||||
map_err(F&& f) &&
|
map_err(F&& f) &&
|
||||||
{
|
{
|
||||||
if(this->is_err()){return err(f(std::move(this->as_err())));}
|
if(this->is_err()){return err(f(std::move(this->as_err())));}
|
||||||
@@ -491,21 +479,21 @@ struct result
|
|||||||
// F: T -> U
|
// F: T -> U
|
||||||
// retval: U
|
// retval: U
|
||||||
template<typename F, typename U>
|
template<typename F, typename U>
|
||||||
return_type_of_t<F, value_type&>
|
detail::return_type_of_t<F, value_type&>
|
||||||
map_or_else(F&& f, U&& opt) &
|
map_or_else(F&& f, U&& opt) &
|
||||||
{
|
{
|
||||||
if(this->is_err()){return std::forward<U>(opt);}
|
if(this->is_err()){return std::forward<U>(opt);}
|
||||||
return f(this->as_ok());
|
return f(this->as_ok());
|
||||||
}
|
}
|
||||||
template<typename F, typename U>
|
template<typename F, typename U>
|
||||||
return_type_of_t<F, value_type const&>
|
detail::return_type_of_t<F, value_type const&>
|
||||||
map_or_else(F&& f, U&& opt) const&
|
map_or_else(F&& f, U&& opt) const&
|
||||||
{
|
{
|
||||||
if(this->is_err()){return std::forward<U>(opt);}
|
if(this->is_err()){return std::forward<U>(opt);}
|
||||||
return f(this->as_ok());
|
return f(this->as_ok());
|
||||||
}
|
}
|
||||||
template<typename F, typename U>
|
template<typename F, typename U>
|
||||||
return_type_of_t<F, value_type&&>
|
detail::return_type_of_t<F, value_type&&>
|
||||||
map_or_else(F&& f, U&& opt) &&
|
map_or_else(F&& f, U&& opt) &&
|
||||||
{
|
{
|
||||||
if(this->is_err()){return std::forward<U>(opt);}
|
if(this->is_err()){return std::forward<U>(opt);}
|
||||||
@@ -516,21 +504,21 @@ struct result
|
|||||||
// F: E -> U
|
// F: E -> U
|
||||||
// retval: U
|
// retval: U
|
||||||
template<typename F, typename U>
|
template<typename F, typename U>
|
||||||
return_type_of_t<F, error_type&>
|
detail::return_type_of_t<F, error_type&>
|
||||||
map_err_or_else(F&& f, U&& opt) &
|
map_err_or_else(F&& f, U&& opt) &
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return std::forward<U>(opt);}
|
if(this->is_ok()){return std::forward<U>(opt);}
|
||||||
return f(this->as_err());
|
return f(this->as_err());
|
||||||
}
|
}
|
||||||
template<typename F, typename U>
|
template<typename F, typename U>
|
||||||
return_type_of_t<F, error_type const&>
|
detail::return_type_of_t<F, error_type const&>
|
||||||
map_err_or_else(F&& f, U&& opt) const&
|
map_err_or_else(F&& f, U&& opt) const&
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return std::forward<U>(opt);}
|
if(this->is_ok()){return std::forward<U>(opt);}
|
||||||
return f(this->as_err());
|
return f(this->as_err());
|
||||||
}
|
}
|
||||||
template<typename F, typename U>
|
template<typename F, typename U>
|
||||||
return_type_of_t<F, error_type&&>
|
detail::return_type_of_t<F, error_type&&>
|
||||||
map_err_or_else(F&& f, U&& opt) &&
|
map_err_or_else(F&& f, U&& opt) &&
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return std::forward<U>(opt);}
|
if(this->is_ok()){return std::forward<U>(opt);}
|
||||||
@@ -542,21 +530,21 @@ struct result
|
|||||||
// toml::err(error_type) should be convertible to U.
|
// toml::err(error_type) should be convertible to U.
|
||||||
// normally, type U is another result<S, F> and E is convertible to F
|
// normally, type U is another result<S, F> and E is convertible to F
|
||||||
template<typename F>
|
template<typename F>
|
||||||
return_type_of_t<F, value_type&>
|
detail::return_type_of_t<F, value_type&>
|
||||||
and_then(F&& f) &
|
and_then(F&& f) &
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return f(this->as_ok());}
|
if(this->is_ok()){return f(this->as_ok());}
|
||||||
return err(this->as_err());
|
return err(this->as_err());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
return_type_of_t<F, value_type const&>
|
detail::return_type_of_t<F, value_type const&>
|
||||||
and_then(F&& f) const&
|
and_then(F&& f) const&
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return f(this->as_ok());}
|
if(this->is_ok()){return f(this->as_ok());}
|
||||||
return err(this->as_err());
|
return err(this->as_err());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
return_type_of_t<F, value_type&&>
|
detail::return_type_of_t<F, value_type&&>
|
||||||
and_then(F&& f) &&
|
and_then(F&& f) &&
|
||||||
{
|
{
|
||||||
if(this->is_ok()){return f(std::move(this->as_ok()));}
|
if(this->is_ok()){return f(std::move(this->as_ok()));}
|
||||||
@@ -568,21 +556,21 @@ struct result
|
|||||||
// toml::ok(value_type) should be convertible to U.
|
// toml::ok(value_type) should be convertible to U.
|
||||||
// normally, type U is another result<S, F> and T is convertible to S
|
// normally, type U is another result<S, F> and T is convertible to S
|
||||||
template<typename F>
|
template<typename F>
|
||||||
return_type_of_t<F, error_type&>
|
detail::return_type_of_t<F, error_type&>
|
||||||
or_else(F&& f) &
|
or_else(F&& f) &
|
||||||
{
|
{
|
||||||
if(this->is_err()){return f(this->as_err());}
|
if(this->is_err()){return f(this->as_err());}
|
||||||
return ok(this->as_ok());
|
return ok(this->as_ok());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
return_type_of_t<F, error_type const&>
|
detail::return_type_of_t<F, error_type const&>
|
||||||
or_else(F&& f) const&
|
or_else(F&& f) const&
|
||||||
{
|
{
|
||||||
if(this->is_err()){return f(this->as_err());}
|
if(this->is_err()){return f(this->as_err());}
|
||||||
return ok(this->as_ok());
|
return ok(this->as_ok());
|
||||||
}
|
}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
return_type_of_t<F, error_type&&>
|
detail::return_type_of_t<F, error_type&&>
|
||||||
or_else(F&& f) &&
|
or_else(F&& f) &&
|
||||||
{
|
{
|
||||||
if(this->is_err()){return f(std::move(this->as_err()));}
|
if(this->is_err()){return f(std::move(this->as_err()));}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ namespace detail
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using unwrap_t = typename std::decay<T>::type;
|
using unwrap_t = typename std::decay<T>::type;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// check whether type T is a kind of container/map class
|
||||||
|
|
||||||
struct has_iterator_impl
|
struct has_iterator_impl
|
||||||
{
|
{
|
||||||
template<typename T> static std::true_type check(typename T::iterator*);
|
template<typename T> static std::true_type check(typename T::iterator*);
|
||||||
@@ -63,6 +66,9 @@ struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){}
|
|||||||
#undef decltype(...)
|
#undef decltype(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// C++17 and/or/not
|
||||||
|
|
||||||
template<typename ...> struct conjunction : std::true_type{};
|
template<typename ...> struct conjunction : std::true_type{};
|
||||||
template<typename T> struct conjunction<T> : T{};
|
template<typename T> struct conjunction<T> : T{};
|
||||||
template<typename T, typename ... Ts>
|
template<typename T, typename ... Ts>
|
||||||
@@ -80,6 +86,9 @@ struct disjunction<T, Ts...> :
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// normal type checker
|
||||||
|
|
||||||
template<typename T> struct is_std_pair : std::false_type{};
|
template<typename T> struct is_std_pair : std::false_type{};
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};
|
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};
|
||||||
@@ -92,7 +101,9 @@ template<typename T> struct is_chrono_duration: std::false_type{};
|
|||||||
template<typename Rep, typename Period>
|
template<typename Rep, typename Period>
|
||||||
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
||||||
|
|
||||||
// to use toml::get<std::tuple<T1, T2, ...>> in C++11
|
// ---------------------------------------------------------------------------
|
||||||
|
// C++14 index_sequence
|
||||||
|
|
||||||
template<std::size_t ... Ns> struct index_sequence{};
|
template<std::size_t ... Ns> struct index_sequence{};
|
||||||
|
|
||||||
template<typename IS, std::size_t N> struct push_back_index_sequence{};
|
template<typename IS, std::size_t N> struct push_back_index_sequence{};
|
||||||
@@ -116,6 +127,21 @@ struct index_sequence_maker<0>
|
|||||||
template<std::size_t N>
|
template<std::size_t N>
|
||||||
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// return_type_of_t
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
|
||||||
|
template<typename F, typename ... Args>
|
||||||
|
using return_type_of_t = std::invoke_result_t<F, Args...>;
|
||||||
|
|
||||||
|
#else
|
||||||
|
// result_of is deprecated after C++17
|
||||||
|
template<typename F, typename ... Args>
|
||||||
|
using return_type_of_t = typename std::result_of<F(Args...)>::type;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
}// detail
|
}// detail
|
||||||
}//toml
|
}//toml
|
||||||
#endif // TOML_TRAITS
|
#endif // TOML_TRAITS
|
||||||
|
|||||||
@@ -137,17 +137,6 @@ template<> struct toml_value_t<LocalDate >{static constexpr value_t value =
|
|||||||
template<> struct toml_value_t<LocalTime >{static constexpr value_t value = value_t::LocalTime ;};
|
template<> struct toml_value_t<LocalTime >{static constexpr value_t value = value_t::LocalTime ;};
|
||||||
template<> struct toml_value_t<Array >{static constexpr value_t value = value_t::Array ;};
|
template<> struct toml_value_t<Array >{static constexpr value_t value = value_t::Array ;};
|
||||||
template<> struct toml_value_t<Table >{static constexpr value_t value = value_t::Table ;};
|
template<> struct toml_value_t<Table >{static constexpr value_t value = value_t::Table ;};
|
||||||
template<typename T> constexpr value_t toml_value_t<T>::value;
|
|
||||||
constexpr value_t toml_value_t<Boolean >::value;
|
|
||||||
constexpr value_t toml_value_t<Integer >::value;
|
|
||||||
constexpr value_t toml_value_t<Float >::value;
|
|
||||||
constexpr value_t toml_value_t<String >::value;
|
|
||||||
constexpr value_t toml_value_t<OffsetDatetime>::value;
|
|
||||||
constexpr value_t toml_value_t<LocalDatetime >::value;
|
|
||||||
constexpr value_t toml_value_t<LocalDate >::value;
|
|
||||||
constexpr value_t toml_value_t<LocalTime >::value;
|
|
||||||
constexpr value_t toml_value_t<Array >::value;
|
|
||||||
constexpr value_t toml_value_t<Table >::value;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_exact_toml_type : disjunction<
|
struct is_exact_toml_type : disjunction<
|
||||||
|
|||||||
@@ -767,6 +767,8 @@ inline bool operator<(const toml::value& lhs, const toml::value& rhs)
|
|||||||
return lhs.cast<value_t::Float >() < rhs.cast<value_t::Float >();
|
return lhs.cast<value_t::Float >() < rhs.cast<value_t::Float >();
|
||||||
case value_t::String :
|
case value_t::String :
|
||||||
return lhs.cast<value_t::String >() < rhs.cast<value_t::String >();
|
return lhs.cast<value_t::String >() < rhs.cast<value_t::String >();
|
||||||
|
case value_t::OffsetDatetime:
|
||||||
|
return lhs.cast<value_t::OffsetDatetime>() < rhs.cast<value_t::OffsetDatetime>();
|
||||||
case value_t::LocalDatetime:
|
case value_t::LocalDatetime:
|
||||||
return lhs.cast<value_t::LocalDatetime>() < rhs.cast<value_t::LocalDatetime>();
|
return lhs.cast<value_t::LocalDatetime>() < rhs.cast<value_t::LocalDatetime>();
|
||||||
case value_t::LocalDate:
|
case value_t::LocalDate:
|
||||||
@@ -801,17 +803,21 @@ inline bool operator>=(const toml::value& lhs, const toml::value& rhs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline std::string format_error(const std::string& err_msg,
|
inline std::string format_error(const std::string& err_msg,
|
||||||
const toml::value& v, const std::string& comment)
|
const toml::value& v, const std::string& comment,
|
||||||
|
std::vector<std::string> hints = {})
|
||||||
{
|
{
|
||||||
return detail::format_underline(err_msg, detail::get_region(v), comment);
|
return detail::format_underline(err_msg, detail::get_region(v), comment,
|
||||||
|
std::move(hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string format_error(const std::string& err_msg,
|
inline std::string format_error(const std::string& err_msg,
|
||||||
const toml::value& v1, const std::string& comment1,
|
const toml::value& v1, const std::string& comment1,
|
||||||
const toml::value& v2, const std::string& comment2)
|
const toml::value& v2, const std::string& comment2,
|
||||||
|
std::vector<std::string> hints = {})
|
||||||
{
|
{
|
||||||
return detail::format_underline(err_msg, detail::get_region(v1), comment1,
|
return detail::format_underline(err_msg, detail::get_region(v1), comment1,
|
||||||
detail::get_region(v2), comment2);
|
detail::get_region(v2), comment2,
|
||||||
|
std::move(hints));
|
||||||
}
|
}
|
||||||
|
|
||||||
}// toml
|
}// toml
|
||||||
|
|||||||
Reference in New Issue
Block a user