Merge pull request #54 from ToruNiina/hotfix

fix: resolve ambiguity in the `""_toml` literal
This commit is contained in:
Toru Niina
2019-04-15 13:34:35 +09:00
committed by GitHub
3 changed files with 81 additions and 4 deletions

View File

@@ -603,6 +603,25 @@ toml::value operator""_toml(const char* str, std::size_t len);
Access to the operator can be gained with `using namespace toml::literals;`, Access to the operator can be gained with `using namespace toml::literals;`,
`using namespace toml::toml_literals`, and `using namespace toml::literals::toml_literals`. `using namespace toml::toml_literals`, and `using namespace toml::literals::toml_literals`.
Note that since it allows a bare value without a key, it is difficult to distinguish
arrays and table definitions.
Currently, it parses `[1]` as a table definition if there are no commas.
To ensure a literal to be considered as an array with one element, you need to
add a comma after the first element (like `[1,]`).
```cpp
"[1,2,3]"_toml; // This is an array
"[table]"_toml; // This is a table that has an empty table named "table" inside.
"[[1,2,3]]"_toml; // This is an array of arrays
"[[table]]"_toml; // This is a table that has an array of tables inside.
"[[1]]"_toml; // This is ambiguous.
// Currently, it becomes a table taht has array of table "1".
"1 = [{}]"_toml; // This is a table that has an array of table named 1.
"[[1,]]"_toml; // This is an array of arrays.
"[[1],]"_toml; // ditto.
```
## Conversion between toml value and arbitrary types ## Conversion between toml value and arbitrary types
You can also use `toml::get` and other related functions with the types you defined You can also use `toml::get` and other related functions with the types you defined

View File

@@ -33,6 +33,18 @@ BOOST_AUTO_TEST_CASE(test_file_as_literal)
b = "baz" b = "baz"
)"_toml; )"_toml;
BOOST_CHECK_EQUAL(r, v);
}
{
const toml::value r{
{"table", toml::table{{"a", 42}, {"b", "baz"}}}
};
const toml::value v = u8R"(
[table]
a = 42
b = "baz"
)"_toml;
BOOST_CHECK_EQUAL(r, v); BOOST_CHECK_EQUAL(r, v);
} }
} }
@@ -91,6 +103,19 @@ BOOST_AUTO_TEST_CASE(test_value_as_literal)
BOOST_CHECK(v1.is_array()); BOOST_CHECK(v1.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3})); BOOST_CHECK((toml::get<std::vector<int>>(v1) == std::vector<int>{1,2,3}));
const toml::value v2 = u8R"([1,])"_toml;
BOOST_CHECK(v2.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(v2) == std::vector<int>{1}));
const toml::value v3 = u8R"([[1,]])"_toml;
BOOST_CHECK(v3.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(toml::get<toml::array>(v3).front()) == std::vector<int>{1}));
const toml::value v4 = u8R"([[1],])"_toml;
BOOST_CHECK(v4.is_array());
BOOST_CHECK((toml::get<std::vector<int>>(toml::get<toml::array>(v4).front()) == std::vector<int>{1}));
} }
{ {
const toml::value v1 = u8R"({a = 42})"_toml; const toml::value v1 = u8R"({a = 42})"_toml;

View File

@@ -30,13 +30,46 @@ inline ::toml::value operator""_toml(const char* str, std::size_t len)
::toml::detail::lex_ws, ::toml::detail::at_least<1>>; ::toml::detail::lex_ws, ::toml::detail::at_least<1>>;
skip_ws::invoke(loc); skip_ws::invoke(loc);
// literal may be a bare value. try them first. // to distinguish arrays and tables, first check it is a table or not.
//
// "[1,2,3]"_toml; // this is an array
// "[table]"_toml; // a table that has an empty table named "table" inside.
// "[[1,2,3]]"_toml; // this is an array of arrays
// "[[table]]"_toml; // this is a table that has an array of tables inside.
//
// "[[1]]"_toml; // this can be both... (currently it becomes a table)
// "1 = [{}]"_toml; // this is a table that has an array of table named 1.
// "[[1,]]"_toml; // this is an array of arrays.
// "[[1],]"_toml; // this also.
const auto the_front = loc.iter();
const bool is_table_key = ::toml::detail::lex_std_table::invoke(loc);
loc.reset(the_front);
const bool is_aots_key = ::toml::detail::lex_array_table::invoke(loc);
loc.reset(the_front);
// If it is neither a table-key or a array-of-table-key, it may be a value.
if(!is_table_key && !is_aots_key)
{
if(auto data = ::toml::detail::parse_value(loc)) if(auto data = ::toml::detail::parse_value(loc))
{ {
return data.unwrap(); return data.unwrap();
} }
}
// Note that still it can be a table, because the literal might be something
// like the following.
// ```cpp
// R"( // c++11 raw string literals
// key = "value"
// int = 42
// )"_toml;
// ```
// It is a valid toml file.
// It should be parsed as if we parse a file with this content.
// literal is a TOML file (i.e. multiline table).
if(auto data = ::toml::detail::parse_toml_file(loc)) if(auto data = ::toml::detail::parse_toml_file(loc))
{ {
loc.reset(loc.begin()); // rollback to the top of the literal loc.reset(loc.begin()); // rollback to the top of the literal