mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Merge pull request #29 from ToruNiina/err-msg-dotted-key
Error message for getting values corresponds to dotted keys
This commit is contained in:
@@ -13,23 +13,23 @@ using namespace detail;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_bare_key)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "barekey", std::vector<key>(1, "barekey"));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "bare-key", std::vector<key>(1, "bare-key"));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "bare_key", std::vector<key>(1, "bare_key"));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "1234", std::vector<key>(1, "1234"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "barekey", std::vector<key>(1, "barekey"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "bare-key", std::vector<key>(1, "bare-key"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "bare_key", std::vector<key>(1, "bare_key"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "1234", std::vector<key>(1, "1234"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_quoted_key)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"127.0.0.1\"", std::vector<key>(1, "127.0.0.1" ));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"character encoding\"", std::vector<key>(1, "character encoding"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"127.0.0.1\"", std::vector<key>(1, "127.0.0.1" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"character encoding\"", std::vector<key>(1, "character encoding"));
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"", std::vector<key>(1, "\xCA\x8E\xC7\x9D\xCA\x9E"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"", std::vector<key>(1, "\xCA\x8E\xC7\x9D\xCA\x9E"));
|
||||
#else
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"ʎǝʞ\"", std::vector<key>(1, "ʎǝʞ" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"ʎǝʞ\"", std::vector<key>(1, "ʎǝʞ" ));
|
||||
#endif
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'key2'", std::vector<key>(1, "key2" ));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'quoted \"value\"'", std::vector<key>(1, "quoted \"value\"" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "'key2'", std::vector<key>(1, "key2" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "'quoted \"value\"'", std::vector<key>(1, "quoted \"value\"" ));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_dotted_key)
|
||||
@@ -38,13 +38,13 @@ BOOST_AUTO_TEST_CASE(test_dotted_key)
|
||||
std::vector<key> keys(2);
|
||||
keys[0] = "physical";
|
||||
keys[1] = "color";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "physical.color", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "physical.color", keys);
|
||||
}
|
||||
{
|
||||
std::vector<key> keys(2);
|
||||
keys[0] = "physical";
|
||||
keys[1] = "shape";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "physical.shape", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "physical.shape", keys);
|
||||
}
|
||||
{
|
||||
std::vector<key> keys(4);
|
||||
@@ -52,12 +52,12 @@ BOOST_AUTO_TEST_CASE(test_dotted_key)
|
||||
keys[1] = "y";
|
||||
keys[2] = "z";
|
||||
keys[3] = "w";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "x.y.z.w", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "x.y.z.w", keys);
|
||||
}
|
||||
{
|
||||
std::vector<key> keys(2);
|
||||
keys[0] = "site";
|
||||
keys[1] = "google.com";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "site.\"google.com\"", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "site.\"google.com\"", keys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,19 +754,21 @@ parse_offset_datetime(location<Container>& loc)
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
result<key, std::string> parse_simple_key(location<Container>& loc)
|
||||
result<std::pair<key, region<Container>>, std::string>
|
||||
parse_simple_key(location<Container>& loc)
|
||||
{
|
||||
if(const auto bstr = parse_basic_string(loc))
|
||||
{
|
||||
return ok(bstr.unwrap().first.str);
|
||||
return ok(std::make_pair(bstr.unwrap().first.str, bstr.unwrap().second));
|
||||
}
|
||||
if(const auto lstr = parse_literal_string(loc))
|
||||
{
|
||||
return ok(lstr.unwrap().first.str);
|
||||
return ok(std::make_pair(lstr.unwrap().first.str, lstr.unwrap().second));
|
||||
}
|
||||
if(const auto bare = lex_unquoted_key::invoke(loc))
|
||||
{
|
||||
return ok(bare.unwrap().str());
|
||||
const auto reg = bare.unwrap();
|
||||
return ok(std::make_pair(reg.str(), reg));
|
||||
}
|
||||
return err(format_underline("[error] toml::parse_simple_key: ", loc,
|
||||
"the next token is not a simple key"));
|
||||
@@ -774,13 +776,15 @@ result<key, std::string> parse_simple_key(location<Container>& loc)
|
||||
|
||||
// dotted key become vector of keys
|
||||
template<typename Container>
|
||||
result<std::vector<key>, std::string> parse_key(location<Container>& loc)
|
||||
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
||||
parse_key(location<Container>& loc)
|
||||
{
|
||||
const auto first = loc.iter();
|
||||
// dotted key -> foo.bar.baz whitespaces are allowed
|
||||
if(const auto token = lex_dotted_key::invoke(loc))
|
||||
{
|
||||
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||
const auto reg = token.unwrap();
|
||||
location<std::string> inner_loc(loc.name(), reg.str());
|
||||
std::vector<key> keys;
|
||||
|
||||
while(inner_loc.iter() != inner_loc.end())
|
||||
@@ -788,7 +792,7 @@ result<std::vector<key>, std::string> parse_key(location<Container>& loc)
|
||||
lex_ws::invoke(inner_loc);
|
||||
if(const auto k = parse_simple_key(inner_loc))
|
||||
{
|
||||
keys.push_back(k.unwrap());
|
||||
keys.push_back(k.unwrap().first);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -813,14 +817,15 @@ result<std::vector<key>, std::string> parse_key(location<Container>& loc)
|
||||
"should be `.`"));
|
||||
}
|
||||
}
|
||||
return ok(keys);
|
||||
return ok(std::make_pair(keys, reg));
|
||||
}
|
||||
loc.iter() = first;
|
||||
|
||||
// simple key -> foo
|
||||
if(const auto smpl = parse_simple_key(loc))
|
||||
{
|
||||
return ok(std::vector<key>(1, smpl.unwrap()));
|
||||
return ok(std::make_pair(std::vector<key>(1, smpl.unwrap().first),
|
||||
smpl.unwrap().second));
|
||||
}
|
||||
return err(format_underline("[error] toml::parse_key: ", loc, "is not a valid key"));
|
||||
}
|
||||
@@ -899,14 +904,14 @@ parse_array(location<Container>& loc)
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
result<std::pair<std::vector<key>, value>, std::string>
|
||||
result<std::pair<std::pair<std::vector<key>, region<Container>>, value>, std::string>
|
||||
parse_key_value_pair(location<Container>& loc)
|
||||
{
|
||||
const auto first = loc.iter();
|
||||
auto key = parse_key(loc);
|
||||
if(!key)
|
||||
auto key_reg = parse_key(loc);
|
||||
if(!key_reg)
|
||||
{
|
||||
std::string msg = std::move(key.unwrap_err());
|
||||
std::string msg = std::move(key_reg.unwrap_err());
|
||||
// if the next token is keyvalue-separator, it means that there are no
|
||||
// key. then we need to show error as "empty key is not allowed".
|
||||
if(const auto keyval_sep = lex_keyval_sep::invoke(loc))
|
||||
@@ -962,7 +967,8 @@ parse_key_value_pair(location<Container>& loc)
|
||||
loc.iter() = first;
|
||||
return err(msg);
|
||||
}
|
||||
return ok(std::make_pair(std::move(key.unwrap()), std::move(val.unwrap())));
|
||||
return ok(std::make_pair(std::move(key_reg.unwrap()),
|
||||
std::move(val.unwrap())));
|
||||
}
|
||||
|
||||
// for error messages.
|
||||
@@ -981,10 +987,11 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last)
|
||||
return retval;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
template<typename InputIterator, typename Container>
|
||||
result<bool, std::string>
|
||||
insert_nested_key(table& root, const toml::value& v,
|
||||
InputIterator iter, const InputIterator last,
|
||||
region<Container> key_reg,
|
||||
const bool is_array_of_table = false)
|
||||
{
|
||||
static_assert(std::is_same<key,
|
||||
@@ -1066,11 +1073,7 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
}
|
||||
else // if not, we need to create the array of table
|
||||
{
|
||||
toml::value aot(v); // copy region info from table to array
|
||||
// update content by an array with one element
|
||||
detail::assign_keeping_region(aot,
|
||||
::toml::value(toml::array(1, v)));
|
||||
|
||||
toml::value aot(toml::array(1, v), key_reg);
|
||||
tab->insert(std::make_pair(k, aot));
|
||||
return ok(true);
|
||||
}
|
||||
@@ -1119,10 +1122,7 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
// [x.y.z]
|
||||
if(tab->count(k) == 0)
|
||||
{
|
||||
// the region of [x.y] is the same as [x.y.z].
|
||||
(*tab)[k] = v; // copy region_info_
|
||||
detail::assign_keeping_region((*tab)[k],
|
||||
::toml::value(::toml::table{}));
|
||||
(*tab)[k] = toml::value(toml::table{}, key_reg);
|
||||
}
|
||||
|
||||
// type checking...
|
||||
@@ -1186,11 +1186,12 @@ parse_inline_table(location<Container>& loc)
|
||||
{
|
||||
return err(kv_r.unwrap_err());
|
||||
}
|
||||
const std::vector<key>& keys = kv_r.unwrap().first;
|
||||
const value& val = kv_r.unwrap().second;
|
||||
const std::vector<key>& keys = kv_r.unwrap().first.first;
|
||||
const region<Container>& key_reg = kv_r.unwrap().first.second;
|
||||
const value& val = kv_r.unwrap().second;
|
||||
|
||||
const auto inserted =
|
||||
insert_nested_key(retval, val, keys.begin(), keys.end());
|
||||
insert_nested_key(retval, val, keys.begin(), keys.end(), key_reg);
|
||||
if(!inserted)
|
||||
{
|
||||
throw internal_error("[error] toml::parse_inline_table: "
|
||||
@@ -1288,7 +1289,7 @@ parse_table_key(location<Container>& loc)
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_table_key: no `]`", inner_loc, "should be `]`"));
|
||||
}
|
||||
return ok(std::make_pair(keys.unwrap(), token.unwrap()));
|
||||
return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1326,7 +1327,7 @@ parse_array_table_key(location<Container>& loc)
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_table_key: no `]]`", inner_loc, "should be `]]`"));
|
||||
}
|
||||
return ok(std::make_pair(keys.unwrap(), token.unwrap()));
|
||||
return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1367,10 +1368,11 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
||||
|
||||
if(const auto kv = parse_key_value_pair(loc))
|
||||
{
|
||||
const std::vector<key>& keys = kv.unwrap().first;
|
||||
const value& val = kv.unwrap().second;
|
||||
const std::vector<key>& keys = kv.unwrap().first.first;
|
||||
const region<Container>& key_reg = kv.unwrap().first.second;
|
||||
const value& val = kv.unwrap().second;
|
||||
const auto inserted =
|
||||
insert_nested_key(tab, val, keys.begin(), keys.end());
|
||||
insert_nested_key(tab, val, keys.begin(), keys.end(), key_reg);
|
||||
if(!inserted)
|
||||
{
|
||||
return err(inserted.unwrap_err());
|
||||
@@ -1448,7 +1450,8 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
|
||||
|
||||
const auto inserted = insert_nested_key(data,
|
||||
toml::value(tab.unwrap(), reg),
|
||||
keys.begin(), keys.end(), /*is_array_of_table=*/ true);
|
||||
keys.begin(), keys.end(), reg,
|
||||
/*is_array_of_table=*/ true);
|
||||
if(!inserted) {return err(inserted.unwrap_err());}
|
||||
|
||||
continue;
|
||||
@@ -1462,7 +1465,7 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
|
||||
const auto& reg = tabkey.unwrap().second;
|
||||
|
||||
const auto inserted = insert_nested_key(data,
|
||||
toml::value(tab.unwrap(), reg), keys.begin(), keys.end());
|
||||
toml::value(tab.unwrap(), reg), keys.begin(), keys.end(), reg);
|
||||
if(!inserted) {return err(inserted.unwrap_err());}
|
||||
|
||||
continue;
|
||||
|
||||
@@ -21,8 +21,6 @@ namespace detail
|
||||
{
|
||||
// to show error messages. not recommended for users.
|
||||
region_base const& get_region(const value&);
|
||||
// ditto.
|
||||
void assign_keeping_region(value&, value);
|
||||
}// detail
|
||||
|
||||
template<typename T>
|
||||
@@ -562,9 +560,6 @@ class value
|
||||
// for error messages
|
||||
friend region_base const& detail::get_region(const value&);
|
||||
|
||||
// to see why it's here, see detail::insert_nested_key.
|
||||
friend void detail::assign_keeping_region(value&, value);
|
||||
|
||||
template<value_t T>
|
||||
struct switch_cast;
|
||||
|
||||
@@ -599,36 +594,8 @@ inline region_base const& get_region(const value& v)
|
||||
{
|
||||
return *(v.region_info_);
|
||||
}
|
||||
// If we keep region information after assigning another toml::* types, the
|
||||
// error message become different from the actual value contained.
|
||||
// To avoid this kind of confusing phenomena, the default assigners clear the
|
||||
// old region_info_. But this functionality is actually needed deep inside of
|
||||
// parser, so if you want to see the usecase, see toml::detail::insert_nested_key
|
||||
// defined in toml/parser.hpp.
|
||||
inline void assign_keeping_region(value& v, value other)
|
||||
{
|
||||
v.cleanup(); // this keeps region info
|
||||
// keep region_info_ intact
|
||||
v.type_ = other.type();
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::Boolean : ::toml::value::assigner(v.boolean_ , other.boolean_ ); break;
|
||||
case value_t::Integer : ::toml::value::assigner(v.integer_ , other.integer_ ); break;
|
||||
case value_t::Float : ::toml::value::assigner(v.floating_ , other.floating_ ); break;
|
||||
case value_t::String : ::toml::value::assigner(v.string_ , other.string_ ); break;
|
||||
case value_t::OffsetDatetime: ::toml::value::assigner(v.offset_datetime_, other.offset_datetime_); break;
|
||||
case value_t::LocalDatetime : ::toml::value::assigner(v.local_datetime_ , other.local_datetime_ ); break;
|
||||
case value_t::LocalDate : ::toml::value::assigner(v.local_date_ , other.local_date_ ); break;
|
||||
case value_t::LocalTime : ::toml::value::assigner(v.local_time_ , other.local_time_ ); break;
|
||||
case value_t::Array : ::toml::value::assigner(v.array_ , other.array_ ); break;
|
||||
case value_t::Table : ::toml::value::assigner(v.table_ , other.table_ ); break;
|
||||
default: break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}// detail
|
||||
|
||||
|
||||
template<> struct value::switch_cast<value_t::Boolean>
|
||||
{
|
||||
static Boolean& invoke(value& v) {return v.boolean_;}
|
||||
|
||||
Reference in New Issue
Block a user