diff --git a/tests/test_parse_key.cpp b/tests/test_parse_key.cpp index b7fcf5b..f05c26b 100644 --- a/tests/test_parse_key.cpp +++ b/tests/test_parse_key.cpp @@ -13,23 +13,23 @@ using namespace detail; BOOST_AUTO_TEST_CASE(test_bare_key) { - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "barekey", std::vector(1, "barekey")); - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "bare-key", std::vector(1, "bare-key")); - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "bare_key", std::vector(1, "bare_key")); - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "1234", std::vector(1, "1234")); + TOML11_TEST_PARSE_EQUAL(parse_key, "barekey", std::vector(1, "barekey")); + TOML11_TEST_PARSE_EQUAL(parse_key, "bare-key", std::vector(1, "bare-key")); + TOML11_TEST_PARSE_EQUAL(parse_key, "bare_key", std::vector(1, "bare_key")); + TOML11_TEST_PARSE_EQUAL(parse_key, "1234", std::vector(1, "1234")); } BOOST_AUTO_TEST_CASE(test_quoted_key) { - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"127.0.0.1\"", std::vector(1, "127.0.0.1" )); - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"character encoding\"", std::vector(1, "character encoding")); + TOML11_TEST_PARSE_EQUAL(parse_key, "\"127.0.0.1\"", std::vector(1, "127.0.0.1" )); + TOML11_TEST_PARSE_EQUAL(parse_key, "\"character encoding\"", std::vector(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(1, "\xCA\x8E\xC7\x9D\xCA\x9E")); + TOML11_TEST_PARSE_EQUAL(parse_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"", std::vector(1, "\xCA\x8E\xC7\x9D\xCA\x9E")); #else - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"ʎǝʞ\"", std::vector(1, "ʎǝʞ" )); + TOML11_TEST_PARSE_EQUAL(parse_key, "\"ʎǝʞ\"", std::vector(1, "ʎǝʞ" )); #endif - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'key2'", std::vector(1, "key2" )); - TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'quoted \"value\"'", std::vector(1, "quoted \"value\"" )); + TOML11_TEST_PARSE_EQUAL(parse_key, "'key2'", std::vector(1, "key2" )); + TOML11_TEST_PARSE_EQUAL(parse_key, "'quoted \"value\"'", std::vector(1, "quoted \"value\"" )); } BOOST_AUTO_TEST_CASE(test_dotted_key) @@ -38,13 +38,13 @@ BOOST_AUTO_TEST_CASE(test_dotted_key) std::vector 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 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 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 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); } } diff --git a/toml/parser.hpp b/toml/parser.hpp index 2b12f2c..faa7213 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -754,19 +754,21 @@ parse_offset_datetime(location& loc) } template -result parse_simple_key(location& loc) +result>, std::string> +parse_simple_key(location& 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 parse_simple_key(location& loc) // dotted key become vector of keys template -result, std::string> parse_key(location& loc) +result, region>, std::string> +parse_key(location& loc) { const auto first = loc.iter(); // dotted key -> foo.bar.baz whitespaces are allowed if(const auto token = lex_dotted_key::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + const auto reg = token.unwrap(); + location inner_loc(loc.name(), reg.str()); std::vector keys; while(inner_loc.iter() != inner_loc.end()) @@ -788,7 +792,7 @@ result, std::string> parse_key(location& 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::string> parse_key(location& 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(1, smpl.unwrap())); + return ok(std::make_pair(std::vector(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& loc) } template -result, value>, std::string> +result, region>, value>, std::string> parse_key_value_pair(location& 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& 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 +template result insert_nested_key(table& root, const toml::value& v, InputIterator iter, const InputIterator last, + region key_reg, const bool is_array_of_table = false) { static_assert(std::is_sameinsert(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& loc) { return err(kv_r.unwrap_err()); } - const std::vector& keys = kv_r.unwrap().first; - const value& val = kv_r.unwrap().second; + const std::vector& keys = kv_r.unwrap().first.first; + const region& 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& 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& 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 parse_ml_table(location& loc) if(const auto kv = parse_key_value_pair(loc)) { - const std::vector& keys = kv.unwrap().first; - const value& val = kv.unwrap().second; + const std::vector& keys = kv.unwrap().first.first; + const region& 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 parse_toml_file(location& 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 parse_toml_file(location& 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; diff --git a/toml/value.hpp b/toml/value.hpp index d71813c..d6f5f0e 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -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 @@ -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 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 { static Boolean& invoke(value& v) {return v.boolean_;}