diff --git a/tests/test_lex_aux.hpp b/tests/test_lex_aux.hpp index c0d2b16..77f2a9b 100644 --- a/tests/test_lex_aux.hpp +++ b/tests/test_lex_aux.hpp @@ -8,7 +8,7 @@ do { \ const std::string token (tkn); \ const std::string expected(expct); \ - toml::detail::location loc("test", token); \ + toml::detail::location loc("test", token); \ const auto result = lxr::invoke(loc); \ BOOST_TEST(result.is_ok()); \ if(result.is_ok()){ \ @@ -28,7 +28,7 @@ do { \ #define TOML11_TEST_LEX_REJECT(lxr, tkn) \ do { \ const std::string token (tkn); \ - toml::detail::location loc("test", token); \ + toml::detail::location loc("test", token); \ const auto result = lxr::invoke(loc); \ BOOST_TEST(result.is_err()); \ const bool loc_same = (loc.begin() == loc.iter()); \ diff --git a/tests/test_parse_aux.hpp b/tests/test_parse_aux.hpp index 6702181..b9fd07c 100644 --- a/tests/test_parse_aux.hpp +++ b/tests/test_parse_aux.hpp @@ -7,7 +7,7 @@ #define TOML11_TEST_PARSE_EQUAL(psr, tkn, expct) \ do { \ const std::string token(tkn); \ - toml::detail::location loc("test", token); \ + toml::detail::location loc("test", token); \ const auto result = psr(loc); \ BOOST_TEST(result.is_ok()); \ if(result.is_ok()){ \ @@ -23,7 +23,7 @@ do { \ #define TOML11_TEST_PARSE_EQUAL_VALUE(psr, tkn, expct) \ do { \ const std::string token(tkn); \ - toml::detail::location loc("test", token); \ + toml::detail::location loc("test", token); \ const auto result = psr(loc); \ BOOST_TEST(result.is_ok()); \ if(result.is_ok()){ \ diff --git a/tests/test_parse_floating.cpp b/tests/test_parse_floating.cpp index 6b0c680..8ddcb90 100644 --- a/tests/test_parse_floating.cpp +++ b/tests/test_parse_floating.cpp @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(test_inf) { { const std::string token("inf"); - toml::detail::location loc("test", token); + toml::detail::location loc("test", token); const auto r = parse_floating(loc); BOOST_CHECK(r.is_ok()); BOOST_CHECK(std::isinf(r.unwrap().first)); @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(test_inf) } { const std::string token("+inf"); - toml::detail::location loc("test", token); + toml::detail::location loc("test", token); const auto r = parse_floating(loc); BOOST_CHECK(r.is_ok()); BOOST_CHECK(std::isinf(r.unwrap().first)); @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(test_inf) } { const std::string token("-inf"); - toml::detail::location loc("test", token); + toml::detail::location loc("test", token); const auto r = parse_floating(loc); BOOST_CHECK(r.is_ok()); BOOST_CHECK(std::isinf(r.unwrap().first)); @@ -156,21 +156,21 @@ BOOST_AUTO_TEST_CASE(test_nan) { { const std::string token("nan"); - toml::detail::location loc("test", token); + toml::detail::location loc("test", token); const auto r = parse_floating(loc); BOOST_CHECK(r.is_ok()); BOOST_CHECK(std::isnan(r.unwrap().first)); } { const std::string token("+nan"); - toml::detail::location loc("test", token); + toml::detail::location loc("test", token); const auto r = parse_floating(loc); BOOST_CHECK(r.is_ok()); BOOST_CHECK(std::isnan(r.unwrap().first)); } { const std::string token("-nan"); - toml::detail::location loc("test", token); + toml::detail::location loc("test", token); const auto r = parse_floating(loc); BOOST_CHECK(r.is_ok()); BOOST_CHECK(std::isnan(r.unwrap().first)); diff --git a/tests/test_parse_table.cpp b/tests/test_parse_table.cpp index e30e257..cb5baee 100644 --- a/tests/test_parse_table.cpp +++ b/tests/test_parse_table.cpp @@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(test_normal_table) "key2 = 42\n" "key3 = 3.14\n" ); - location loc("test", table); + location loc("test", table); const auto result = toml::detail::parse_ml_table(loc); BOOST_TEST(result.is_ok()); @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(test_nested_table) "a.b = \"value\"\n" "a.c.d = 42\n" ); - location loc("test", table); + location loc("test", table); const auto result = toml::detail::parse_ml_table(loc); BOOST_TEST(result.is_ok()); diff --git a/toml/combinator.hpp b/toml/combinator.hpp index 3d72718..e250188 100644 --- a/toml/combinator.hpp +++ b/toml/combinator.hpp @@ -58,13 +58,9 @@ struct character { static constexpr char target = C; - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); - if(loc.iter() == loc.end()) {return none();} const auto first = loc.iter(); @@ -75,7 +71,7 @@ struct character } loc.advance(); // update location - return ok(region(loc, first, loc.iter())); + return ok(region(loc, first, loc.iter())); } }; template @@ -91,13 +87,9 @@ struct in_range static constexpr char upper = Up; static constexpr char lower = Low; - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); - if(loc.iter() == loc.end()) {return none();} const auto first = loc.iter(); @@ -108,7 +100,7 @@ struct in_range } loc.advance(); - return ok(region(loc, first, loc.iter())); + return ok(region(loc, first, loc.iter())); } }; template constexpr char in_range::upper; @@ -119,13 +111,9 @@ template constexpr char in_range::lower; template struct exclude { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); - if(loc.iter() == loc.end()) {return none();} auto first = loc.iter(); @@ -136,7 +124,7 @@ struct exclude return none(); } loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but... - return ok(region(loc, first, loc.iter())); + return ok(region(loc, first, loc.iter())); } }; @@ -144,19 +132,15 @@ struct exclude template struct maybe { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); - const auto rslt = Combinator::invoke(loc); if(rslt.is_ok()) { return rslt; } - return ok(region(loc)); + return ok(region(loc)); } }; @@ -166,13 +150,9 @@ struct sequence; template struct sequence { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); - const auto first = loc.iter(); const auto rslt = Head::invoke(loc); if(rslt.is_err()) @@ -184,9 +164,9 @@ struct sequence } // called from the above function only, recursively. - template - static result, none_t> - invoke(location& loc, region reg, Iterator first) + template + static result + invoke(location& loc, region reg, Iterator first) { const auto rslt = Head::invoke(loc); if(rslt.is_err()) @@ -203,9 +183,9 @@ template struct sequence { // would be called from sequence::invoke only. - template - static result, none_t> - invoke(location& loc, region reg, Iterator first) + template + static result + invoke(location& loc, region reg, Iterator first) { const auto rslt = Head::invoke(loc); if(rslt.is_err()) @@ -224,13 +204,9 @@ struct either; template struct either { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); - const auto rslt = Head::invoke(loc); if(rslt.is_ok()) {return rslt;} return either::invoke(loc); @@ -239,12 +215,9 @@ struct either template struct either { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - static_assert(std::is_same::value, - "internal error: container::value_type should be `char`."); return Head::invoke(loc); } }; @@ -259,11 +232,10 @@ struct unlimited{}; template struct repeat> { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - region retval(loc); + region retval(loc); const auto first = loc.iter(); for(std::size_t i=0; i> template struct repeat> { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - region retval(loc); + region retval(loc); const auto first = loc.iter(); for(std::size_t i=0; i> template struct repeat { - template - static result, none_t> - invoke(location& loc) + static result + invoke(location& loc) { - region retval(loc); + region retval(loc); while(true) { auto rslt = T::invoke(loc); diff --git a/toml/get.hpp b/toml/get.hpp index 93b834a..3be82bf 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -189,8 +189,7 @@ get(const basic_value& v) { throw type_error(detail::format_underline("toml::value: " "bad_cast to std::chrono::system_clock::time_point", { - {std::addressof(detail::get_region(v)), - concat_to_string("the actual type is ", v.type())} + {v.location(), concat_to_string("the actual type is ", v.type())} }), v.location()); } } @@ -336,7 +335,7 @@ get(const basic_value& v) throw std::out_of_range(detail::format_underline(concat_to_string( "toml::get: specified container size is ", container.size(), " but there are ", ar.size(), " elements in toml array."), { - {std::addressof(detail::get_region(v)), "here"} + {v.location(), "here"} })); } std::transform(ar.cbegin(), ar.cend(), container.begin(), @@ -360,9 +359,7 @@ get(const basic_value& v) { throw std::out_of_range(detail::format_underline(concat_to_string( "toml::get: specified std::pair but there are ", ar.size(), - " elements in toml array."), { - {std::addressof(detail::get_region(v)), "here"} - })); + " elements in toml array."), {{v.location(), "here"}})); } return std::make_pair(::toml::get(ar.at(0)), ::toml::get(ar.at(1))); @@ -392,9 +389,7 @@ get(const basic_value& v) throw std::out_of_range(detail::format_underline(concat_to_string( "toml::get: specified std::tuple with ", std::tuple_size::value, " elements, but there are ", ar.size(), - " elements in toml array."), { - {std::addressof(detail::get_region(v)), "here"} - })); + " elements in toml array."), {{v.location(), "here"}})); } return detail::get_tuple_impl(ar, detail::make_index_sequence::value>{}); @@ -511,9 +506,7 @@ find(const basic_value& v, const std::size_t idx) if(ary.size() <= idx) { throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), { - {std::addressof(detail::get_region(v)), "in this array"} - })); + "index ", idx, " is out of range"), {{v.location(), "in this array"}})); } return ary.at(idx); } @@ -525,9 +518,7 @@ basic_value& find(basic_value& v, const std::size_t idx) if(ary.size() <= idx) { throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), { - {std::addressof(detail::get_region(v)), "in this array"} - })); + "index ", idx, " is out of range"), {{v.location(), "in this array"}})); } return ary.at(idx); } @@ -539,9 +530,7 @@ basic_value find(basic_value&& v, const std::size_t idx) if(ary.size() <= idx) { throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), { - {std::addressof(detail::get_region(v)), "in this array"} - })); + "index ", idx, " is out of range"), {{v.location(), "in this array"}})); } return basic_value(std::move(ary.at(idx))); } @@ -599,9 +588,7 @@ find(const basic_value& v, const std::size_t idx) if(ary.size() <= idx) { throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), { - {std::addressof(detail::get_region(v)), "in this array"} - })); + "index ", idx, " is out of range"), {{v.location(), "in this array"}})); } return ::toml::get(ary.at(idx)); } @@ -614,9 +601,7 @@ find(basic_value& v, const std::size_t idx) if(ary.size() <= idx) { throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), { - {std::addressof(detail::get_region(v)), "in this array"} - })); + "index ", idx, " is out of range"), {{v.location(), "in this array"}})); } return ::toml::get(ary.at(idx)); } @@ -629,9 +614,7 @@ find(basic_value&& v, const std::size_t idx) if(ary.size() <= idx) { throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), { - {std::addressof(detail::get_region(v)), "in this array"} - })); + "index ", idx, " is out of range"), {{v.location(), "in this array"}})); } return ::toml::get(std::move(ary.at(idx))); } diff --git a/toml/literal.hpp b/toml/literal.hpp index 14b6883..5292b3d 100644 --- a/toml/literal.hpp +++ b/toml/literal.hpp @@ -13,7 +13,7 @@ inline namespace toml_literals inline ::toml::value operator"" _toml(const char* str, std::size_t len) { - ::toml::detail::location> + ::toml::detail::location loc(/* filename = */ std::string("TOML literal encoded in a C++ code"), /* contents = */ std::vector(str, str + len)); @@ -76,8 +76,7 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len) } else // none of them. { - throw ::toml::syntax_error(data.unwrap_err(), - source_location(std::addressof(loc))); + throw ::toml::syntax_error(data.unwrap_err(), source_location(loc)); } } diff --git a/toml/parser.hpp b/toml/parser.hpp index 586a0fd..7ef196a 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -25,9 +25,8 @@ namespace toml namespace detail { -template -result>, std::string> -parse_boolean(location& loc) +inline result, std::string> +parse_boolean(location& loc) { const auto first = loc.iter(); if(const auto token = lex_boolean::invoke(loc)) @@ -39,18 +38,17 @@ parse_boolean(location& loc) { throw internal_error(format_underline( "toml::parse_boolean: internal error", - {{std::addressof(reg), "invalid token"}}), - source_location(std::addressof(reg))); + {{source_location(reg), "invalid token"}}), + source_location(reg)); } } loc.reset(first); //rollback return err(format_underline("toml::parse_boolean: ", - {{std::addressof(loc), "the next token is not a boolean"}})); + {{source_location(loc), "the next token is not a boolean"}})); } -template -result>, std::string> -parse_binary_integer(location& loc) +inline result, std::string> +parse_binary_integer(location& loc) { const auto first = loc.iter(); if(const auto token = lex_bin_int::invoke(loc)) @@ -67,20 +65,19 @@ parse_binary_integer(location& loc) { throw internal_error(format_underline( "toml::parse_integer: internal error", - {{std::addressof(token.unwrap()), "invalid token"}}), - source_location(std::addressof(loc))); + {{source_location(token.unwrap()), "invalid token"}}), + source_location(loc)); } } return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); return err(format_underline("toml::parse_binary_integer:", - {{std::addressof(loc), "the next token is not an integer"}})); + {{source_location(loc), "the next token is not an integer"}})); } -template -result>, std::string> -parse_octal_integer(location& loc) +inline result, std::string> +parse_octal_integer(location& loc) { const auto first = loc.iter(); if(const auto token = lex_oct_int::invoke(loc)) @@ -96,12 +93,11 @@ parse_octal_integer(location& loc) } loc.reset(first); return err(format_underline("toml::parse_octal_integer:", - {{std::addressof(loc), "the next token is not an integer"}})); + {{source_location(loc), "the next token is not an integer"}})); } -template -result>, std::string> -parse_hexadecimal_integer(location& loc) +inline result, std::string> +parse_hexadecimal_integer(location& loc) { const auto first = loc.iter(); if(const auto token = lex_hex_int::invoke(loc)) @@ -117,12 +113,11 @@ parse_hexadecimal_integer(location& loc) } loc.reset(first); return err(format_underline("toml::parse_hexadecimal_integer", - {{std::addressof(loc), "the next token is not an integer"}})); + {{source_location(loc), "the next token is not an integer"}})); } -template -result>, std::string> -parse_integer(location& loc) +inline result, std::string> +parse_integer(location& loc) { const auto first = loc.iter(); if(first != loc.end() && *first == '0') @@ -130,7 +125,7 @@ parse_integer(location& loc) const auto second = std::next(first); if(second == loc.end()) // the token is just zero. { - return ok(std::make_pair(0, region(loc, first, second))); + return ok(std::make_pair(0, region(loc, first, second))); } if(*second == 'b') {return parse_binary_integer (loc);} // 0b1100 @@ -141,13 +136,13 @@ parse_integer(location& loc) { return err(format_underline("toml::parse_integer: " "leading zero in an Integer is not allowed.", - {{std::addressof(loc), "leading zero"}})); + {{source_location(loc), "leading zero"}})); } else if(std::isalpha(*second)) { return err(format_underline("toml::parse_integer: " "unknown integer prefix appeared.", - {{std::addressof(loc), "none of 0x, 0o, 0b"}})); + {{source_location(loc), "none of 0x, 0o, 0b"}})); } } @@ -163,12 +158,11 @@ parse_integer(location& loc) } loc.reset(first); return err(format_underline("toml::parse_integer: ", - {{std::addressof(loc), "the next token is not an integer"}})); + {{source_location(loc), "the next token is not an integer"}})); } -template -result>, std::string> -parse_floating(location& loc) +inline result, std::string> +parse_floating(location& loc) { const auto first = loc.iter(); if(const auto token = lex_float::invoke(loc)) @@ -252,12 +246,10 @@ parse_floating(location& loc) } loc.reset(first); return err(format_underline("toml::parse_floating: ", - {{std::addressof(loc), "the next token is not a float"}})); + {{source_location(loc), "the next token is not a float"}})); } -template -std::string read_utf8_codepoint(const region& reg, - /* for err msg */ const location& loc) +inline std::string read_utf8_codepoint(const region& reg, const location& loc) { const auto str = reg.str().substr(1); std::uint_least32_t codepoint; @@ -287,8 +279,8 @@ std::string read_utf8_codepoint(const region& reg, throw syntax_error(format_underline( "toml::read_utf8_codepoint: codepoints in the range " "[0xD800, 0xDFFF] are not valid UTF-8.", {{ - std::addressof(loc), "not a valid UTF-8 codepoint" - }}), source_location(std::addressof(loc))); + source_location(loc), "not a valid UTF-8 codepoint" + }}), source_location(loc)); } assert(codepoint < 0xD800 || 0xDFFF < codepoint); // 1110yyyy 10yxxxxx 10xxxxxx @@ -308,20 +300,19 @@ std::string read_utf8_codepoint(const region& reg, { throw syntax_error(format_underline("toml::read_utf8_codepoint:" " input codepoint is too large.", - {{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "should be in [0x00..0x10FFFF]"}}), + source_location(loc)); } return character; } -template -result parse_escape_sequence(location& loc) +inline result parse_escape_sequence(location& loc) { const auto first = loc.iter(); if(first == loc.end() || *first != '\\') { return err(format_underline("toml::parse_escape_sequence: ", {{ - std::addressof(loc), "the next token is not a backslash \"\\\""}})); + source_location(loc), "the next token is not a backslash \"\\\""}})); } loc.advance(); switch(*loc.iter()) @@ -343,7 +334,7 @@ result parse_escape_sequence(location& loc) { return err(format_underline("parse_escape_sequence: " "invalid token found in UTF-8 codepoint uXXXX.", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } } case 'U': @@ -356,13 +347,13 @@ result parse_escape_sequence(location& loc) { return err(format_underline("parse_escape_sequence: " "invalid token found in UTF-8 codepoint Uxxxxxxxx", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } } } const auto msg = format_underline("parse_escape_sequence: " - "unknown escape sequence appeared.", {{std::addressof(loc), + "unknown escape sequence appeared.", {{source_location(loc), "escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}}, /* Hints = */{"if you want to write backslash as just one backslash, " "use literal string like: regex = '<\\i\\c*\\s*>'"}); @@ -370,9 +361,8 @@ result parse_escape_sequence(location& loc) return err(msg); } -template -result>, std::string> -parse_ml_basic_string(location& loc) +inline result, std::string> +parse_ml_basic_string(location& loc) { const auto first = loc.iter(); if(const auto token = lex_ml_basic_string::invoke(loc)) @@ -388,8 +378,8 @@ parse_ml_basic_string(location& loc) { throw internal_error(format_underline( "parse_ml_basic_string: invalid token", - {{std::addressof(inner_loc), "should be \"\"\""}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be \"\"\""}}), + source_location(inner_loc)); } // immediate newline is ignored (if exists) /* discard return value */ lex_newline::invoke(inner_loc); @@ -415,8 +405,8 @@ parse_ml_basic_string(location& loc) { throw internal_error(format_underline( "parse_ml_basic_string: unexpected end of region", - {{std::addressof(inner_loc), "not sufficient token"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "not sufficient token"}}), + source_location(inner_loc)); } delim = lex_ml_basic_string_close::invoke(inner_loc); } @@ -435,8 +425,8 @@ parse_ml_basic_string(location& loc) { throw internal_error(format_underline( "parse_ml_basic_string: closing delimiter has invalid length", - {{std::addressof(inner_loc), "end of this"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "end of this"}}), + source_location(inner_loc)); } } return ok(std::make_pair(toml::string(retval), token.unwrap())); @@ -446,13 +436,12 @@ parse_ml_basic_string(location& loc) loc.reset(first); return err(format_underline("toml::parse_ml_basic_string: " "the next token is not a valid multiline string", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } } -template -result>, std::string> -parse_basic_string(location& loc) +inline result, std::string> +parse_basic_string(location& loc) { const auto first = loc.iter(); if(const auto token = lex_basic_string::invoke(loc)) @@ -464,8 +453,8 @@ parse_basic_string(location& loc) if(!quot) { throw internal_error(format_underline("parse_basic_string: " - "invalid token", {{std::addressof(inner_loc), "should be \""}}), - source_location(std::addressof(inner_loc))); + "invalid token", {{source_location(inner_loc), "should be \""}}), + source_location(inner_loc)); } std::string retval; @@ -487,8 +476,8 @@ parse_basic_string(location& loc) { throw internal_error(format_underline( "parse_basic_string: unexpected end of region", - {{std::addressof(inner_loc), "not sufficient token"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "not sufficient token"}}), + source_location(inner_loc)); } quot = lex_quotation_mark::invoke(inner_loc); } @@ -499,26 +488,25 @@ parse_basic_string(location& loc) loc.reset(first); // rollback return err(format_underline("toml::parse_basic_string: " "the next token is not a valid string", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } } -template -result>, std::string> -parse_ml_literal_string(location& loc) +inline result, std::string> +parse_ml_literal_string(location& loc) { const auto first = loc.iter(); if(const auto token = lex_ml_literal_string::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto open = lex_ml_literal_string_open::invoke(inner_loc); if(!open) { throw internal_error(format_underline( "parse_ml_literal_string: invalid token", - {{std::addressof(inner_loc), "should be '''"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be '''"}}), + source_location(inner_loc)); } // immediate newline is ignored (if exists) /* discard return value */ lex_newline::invoke(inner_loc); @@ -530,8 +518,8 @@ parse_ml_literal_string(location& loc) { throw internal_error(format_underline( "parse_ml_literal_string: invalid token", - {{std::addressof(inner_loc), "should be '''"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be '''"}}), + source_location(inner_loc)); } // `lex_ml_literal_string_close` allows 3 to 5 `'`s to allow 1 or 2 `'`s // at just before the delimiter. Here, we need to attach `'`s at the @@ -550,8 +538,8 @@ parse_ml_literal_string(location& loc) { throw internal_error(format_underline( "parse_ml_literal_string: closing delimiter has invalid length", - {{std::addressof(inner_loc), "end of this"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "end of this"}}), + source_location(inner_loc)); } } return ok(std::make_pair(toml::string(retval, toml::string_t::literal), @@ -562,26 +550,25 @@ parse_ml_literal_string(location& loc) loc.reset(first); // rollback return err(format_underline("toml::parse_ml_literal_string: " "the next token is not a valid multiline literal string", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } } -template -result>, std::string> -parse_literal_string(location& loc) +inline result, std::string> +parse_literal_string(location& loc) { const auto first = loc.iter(); if(const auto token = lex_literal_string::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto open = lex_apostrophe::invoke(inner_loc); if(!open) { throw internal_error(format_underline( "parse_literal_string: invalid token", - {{std::addressof(inner_loc), "should be '"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be '"}}), + source_location(inner_loc)); } const auto body = repeat::invoke(inner_loc); @@ -591,8 +578,8 @@ parse_literal_string(location& loc) { throw internal_error(format_underline( "parse_literal_string: invalid token", - {{std::addressof(inner_loc), "should be '"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be '"}}), + source_location(inner_loc)); } return ok(std::make_pair( toml::string(body.unwrap().str(), toml::string_t::literal), @@ -603,13 +590,12 @@ parse_literal_string(location& loc) loc.reset(first); // rollback return err(format_underline("toml::parse_literal_string: " "the next token is not a valid literal string", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } } -template -result>, std::string> -parse_string(location& loc) +inline result, std::string> +parse_string(location& loc) { if(loc.iter() != loc.end() && *(loc.iter()) == '"') { @@ -636,25 +622,24 @@ parse_string(location& loc) } } return err(format_underline("toml::parse_string: ", - {{std::addressof(loc), "the next token is not a string"}})); + {{source_location(loc), "the next token is not a string"}})); } -template -result>, std::string> -parse_local_date(location& loc) +inline result, std::string> +parse_local_date(location& loc) { const auto first = loc.iter(); if(const auto token = lex_local_date::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto y = lex_date_fullyear::invoke(inner_loc); if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') { throw internal_error(format_underline( "toml::parse_inner_local_date: invalid year format", - {{std::addressof(inner_loc), "should be `-`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `-`"}}), + source_location(inner_loc)); } inner_loc.advance(); const auto m = lex_date_month::invoke(inner_loc); @@ -662,8 +647,8 @@ parse_local_date(location& loc) { throw internal_error(format_underline( "toml::parse_local_date: invalid month format", - {{std::addressof(inner_loc), "should be `-`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `-`"}}), + source_location(inner_loc)); } inner_loc.advance(); const auto d = lex_date_mday::invoke(inner_loc); @@ -671,8 +656,8 @@ parse_local_date(location& loc) { throw internal_error(format_underline( "toml::parse_local_date: invalid day format", - {{std::addressof(inner_loc), "here"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "here"}}), + source_location(inner_loc)); } return ok(std::make_pair(local_date( static_cast(from_string(y.unwrap().str(), 0)), @@ -685,26 +670,25 @@ parse_local_date(location& loc) { loc.reset(first); return err(format_underline("toml::parse_local_date: ", - {{std::addressof(loc), "the next token is not a local_date"}})); + {{source_location(loc), "the next token is not a local_date"}})); } } -template -result>, std::string> -parse_local_time(location& loc) +inline result, std::string> +parse_local_time(location& loc) { const auto first = loc.iter(); if(const auto token = lex_local_time::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto h = lex_time_hour::invoke(inner_loc); if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') { throw internal_error(format_underline( "toml::parse_local_time: invalid year format", - {{std::addressof(inner_loc), "should be `:`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `:`"}}), + source_location(inner_loc)); } inner_loc.advance(); const auto m = lex_time_minute::invoke(inner_loc); @@ -712,8 +696,8 @@ parse_local_time(location& loc) { throw internal_error(format_underline( "toml::parse_local_time: invalid month format", - {{std::addressof(inner_loc), "should be `:`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `:`"}}), + source_location(inner_loc)); } inner_loc.advance(); const auto s = lex_time_second::invoke(inner_loc); @@ -721,8 +705,8 @@ parse_local_time(location& loc) { throw internal_error(format_underline( "toml::parse_local_time: invalid second format", - {{std::addressof(inner_loc), "here"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "here"}}), + source_location(inner_loc)); } local_time time( from_string(h.unwrap().str(), 0), @@ -764,8 +748,8 @@ parse_local_time(location& loc) { throw internal_error(format_underline( "toml::parse_local_time: invalid subsecond format", - {{std::addressof(inner_loc), "here"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "here"}}), + source_location(inner_loc)); } } return ok(std::make_pair(time, token.unwrap())); @@ -774,33 +758,32 @@ parse_local_time(location& loc) { loc.reset(first); return err(format_underline("toml::parse_local_time: ", - {{std::addressof(loc), "the next token is not a local_time"}})); + {{source_location(loc), "the next token is not a local_time"}})); } } -template -result>, std::string> -parse_local_datetime(location& loc) +inline result, std::string> +parse_local_datetime(location& loc) { const auto first = loc.iter(); if(const auto token = lex_local_date_time::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto date = parse_local_date(inner_loc); if(!date || inner_loc.iter() == inner_loc.end()) { throw internal_error(format_underline( "toml::parse_local_datetime: invalid datetime format", - {{std::addressof(inner_loc), "date, not datetime"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "date, not datetime"}}), + source_location(inner_loc)); } const char delim = *(inner_loc.iter()); if(delim != 'T' && delim != 't' && delim != ' ') { throw internal_error(format_underline( "toml::parse_local_datetime: invalid datetime format", - {{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `T` or ` ` (space)"}}), + source_location(inner_loc)); } inner_loc.advance(); const auto time = parse_local_time(inner_loc); @@ -808,8 +791,8 @@ parse_local_datetime(location& loc) { throw internal_error(format_underline( "toml::parse_local_datetime: invalid datetime format", - {{std::addressof(inner_loc), "invalid time fomrat"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "invalid time fomrat"}}), + source_location(inner_loc)); } return ok(std::make_pair( local_datetime(date.unwrap().first, time.unwrap().first), @@ -819,25 +802,24 @@ parse_local_datetime(location& loc) { loc.reset(first); return err(format_underline("toml::parse_local_datetime: ", - {{std::addressof(loc), "the next token is not a local_datetime"}})); + {{source_location(loc), "the next token is not a local_datetime"}})); } } -template -result>, std::string> -parse_offset_datetime(location& loc) +inline result, std::string> +parse_offset_datetime(location& loc) { const auto first = loc.iter(); if(const auto token = lex_offset_date_time::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto datetime = parse_local_datetime(inner_loc); if(!datetime || inner_loc.iter() == inner_loc.end()) { throw internal_error(format_underline( "toml::parse_offset_datetime: invalid datetime format", - {{std::addressof(inner_loc), "date, not datetime"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "date, not datetime"}}), + source_location(inner_loc)); } time_offset offset(0, 0); if(const auto ofs = lex_time_numoffset::invoke(inner_loc)) @@ -858,8 +840,8 @@ parse_offset_datetime(location& loc) { throw internal_error(format_underline( "toml::parse_offset_datetime: invalid datetime format", - {{std::addressof(inner_loc), "should be `Z` or `+HH:MM`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `Z` or `+HH:MM`"}}), + source_location(inner_loc)); } return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset), token.unwrap())); @@ -868,13 +850,12 @@ parse_offset_datetime(location& loc) { loc.reset(first); return err(format_underline("toml::parse_offset_datetime: ", - {{std::addressof(loc), "the next token is not a offset_datetime"}})); + {{source_location(loc), "the next token is not a offset_datetime"}})); } } -template -result>, std::string> -parse_simple_key(location& loc) +inline result, std::string> +parse_simple_key(location& loc) { if(const auto bstr = parse_basic_string(loc)) { @@ -890,20 +871,19 @@ parse_simple_key(location& loc) return ok(std::make_pair(reg.str(), reg)); } return err(format_underline("toml::parse_simple_key: ", - {{std::addressof(loc), "the next token is not a simple key"}})); + {{source_location(loc), "the next token is not a simple key"}})); } // dotted key become vector of keys -template -result, region>, std::string> -parse_key(location& loc) +inline 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)) { const auto reg = token.unwrap(); - location inner_loc(loc.name(), reg.str()); + location inner_loc(loc.name(), reg.str()); std::vector keys; while(inner_loc.iter() != inner_loc.end()) @@ -917,8 +897,8 @@ parse_key(location& loc) { throw internal_error(format_underline( "toml::detail::parse_key: dotted key contains invalid key", - {{std::addressof(inner_loc), k.unwrap_err()}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), k.unwrap_err()}}), + source_location(inner_loc)); } lex_ws::invoke(inner_loc); @@ -934,8 +914,8 @@ parse_key(location& loc) { throw internal_error(format_underline("toml::parse_key: " "dotted key contains invalid key ", - {{std::addressof(inner_loc), "should be `.`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `.`"}}), + source_location(inner_loc)); } } return ok(std::make_pair(keys, reg)); @@ -949,16 +929,16 @@ parse_key(location& loc) smpl.unwrap().second)); } return err(format_underline("toml::parse_key: ", - {{std::addressof(loc), "is not a valid key"}})); + {{source_location(loc), "is not a valid key"}})); } // forward-decl to implement parse_array and parse_table -template -result parse_value(location&); +template +result parse_value(location&); -template -result>, std::string> -parse_array(location& loc) +template +result, std::string> +parse_array(location& loc) { using value_type = Value; using array_type = typename value_type::array_type; @@ -986,7 +966,7 @@ parse_array(location& loc) { loc.advance(); // skip ']' return ok(std::make_pair(retval, - region(loc, first, loc.iter()))); + region(loc, first, loc.iter()))); } if(auto val = parse_value(loc)) @@ -1004,16 +984,16 @@ parse_array(location& loc) throw syntax_error(format_underline("toml::parse_array: " "type of elements should be the same each other.", { - {std::addressof(array_start_loc), "array starts here"}, + {source_location(array_start_loc), "array starts here"}, { - std::addressof(get_region(retval.front())), + retval.front().location(), "value has type " + stringize(retval.front().type()) }, { - std::addressof(get_region(val.unwrap())), + val.unwrap().location(), "value has different type, " + stringize(val.unwrap().type()) } - }), source_location(std::addressof(loc))); + }), source_location(loc)); } #endif retval.push_back(std::move(val.unwrap())); @@ -1025,9 +1005,9 @@ parse_array(location& loc) throw syntax_error(format_underline("toml::parse_array: " "value having invalid format appeared in an array", { - {std::addressof(array_start_loc), "array starts here"}, - {std::addressof(loc), "it is not a valid value."} - }), source_location(std::addressof(loc))); + {source_location(array_start_loc), "array starts here"}, + {source_location(loc), "it is not a valid value."} + }), source_location(loc)); } using lex_array_separator = sequence, character<','>>; @@ -1039,7 +1019,7 @@ parse_array(location& loc) { loc.advance(); // skip ']' return ok(std::make_pair(retval, - region(loc, first, loc.iter()))); + region(loc, first, loc.iter()))); } else { @@ -1048,22 +1028,22 @@ parse_array(location& loc) throw syntax_error(format_underline("toml::parse_array:" " missing array separator `,` after a value", { - {std::addressof(array_start_loc), "array starts here"}, - {std::addressof(loc), "should be `,`"} - }), source_location(std::addressof(loc))); + {source_location(array_start_loc), "array starts here"}, + {source_location(loc), "should be `,`"} + }), source_location(loc)); } } } loc.reset(first); throw syntax_error(format_underline("toml::parse_array: " "array did not closed by `]`", - {{std::addressof(loc), "should be closed"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "should be closed"}}), + source_location(loc)); } -template -result, region>, Value>, std::string> -parse_key_value_pair(location& loc) +template +result, region>, Value>, std::string> +parse_key_value_pair(location& loc) { using value_type = Value; @@ -1079,7 +1059,7 @@ parse_key_value_pair(location& loc) loc.reset(first); msg = format_underline("toml::parse_key_value_pair: " "empty key is not allowed.", - {{std::addressof(loc), "key expected before '='"}}); + {{source_location(loc), "key expected before '='"}}); } return err(std::move(msg)); } @@ -1095,7 +1075,7 @@ parse_key_value_pair(location& loc) { msg = format_underline("toml::parse_key_value_pair: " "invalid format for key", - {{std::addressof(loc), "invalid character in key"}}, + {{source_location(loc), "invalid character in key"}}, {"Did you forget '.' to separate dotted-key?", "Allowed characters for bare key are [0-9a-zA-Z_-]."}); } @@ -1103,7 +1083,7 @@ parse_key_value_pair(location& loc) { msg = format_underline("toml::parse_key_value_pair: " "missing key-value separator `=`", - {{std::addressof(loc), "should be `=`"}}); + {{source_location(loc), "should be `=`"}}); } loc.reset(first); return err(std::move(msg)); @@ -1121,7 +1101,7 @@ parse_key_value_pair(location& loc) loc.reset(after_kvsp); msg = format_underline("toml::parse_key_value_pair: " "missing value after key-value separator '='", - {{std::addressof(loc), "expected value, but got nothing"}}); + {{source_location(loc), "expected value, but got nothing"}}); } else // there is something not a comment/whitespace, so invalid format. { @@ -1151,9 +1131,8 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last) } // forward decl for is_valid_forward_table_definition -template -result, region>, std::string> -parse_table_key(location& loc); +result, region>, std::string> +parse_table_key(location& loc); // The following toml file is allowed. // ```toml @@ -1182,7 +1161,12 @@ template bool is_valid_forward_table_definition(const Value& fwd, Iterator key_first, Iterator key_curr, Iterator key_last) { - location def("internal", detail::get_region(fwd).str()); + std::string internal = ""; + if(const auto ptr = detail::get_region(fwd)) + { + internal = ptr->str(); + } + location def("internal", std::move(internal)); if(const auto tabkeys = parse_table_key(def)) { // table keys always contains all the nodes from the root. @@ -1220,11 +1204,11 @@ bool is_valid_forward_table_definition(const Value& fwd, return false; } -template +template result insert_nested_key(typename Value::table_type& root, const Value& v, InputIterator iter, const InputIterator last, - region key_reg, + region key_reg, const bool is_array_of_table = false) { static_assert(std::is_sameat(k))), - "table already defined"}, - {std::addressof(get_region(v)), - "this conflicts with the previous table"} + {tab->at(k).location(), "table already defined"}, + {v.location(), "this conflicts with the previous table"} }), v.location()); } else if(!(tab->at(k).is_array())) @@ -1269,10 +1251,10 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") collides with" " existing value"), { - {std::addressof(get_region(tab->at(k))), + {tab->at(k).location(), concat_to_string("this ", tab->at(k).type(), " value already exists")}, - {std::addressof(get_region(v)), + {v.location(), "while inserting this array-of-tables"} }), v.location()); } @@ -1284,10 +1266,10 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") collides with" " existing value"), { - {std::addressof(get_region(tab->at(k))), + {tab->at(k).location(), concat_to_string("this ", tab->at(k).type(), " value already exists")}, - {std::addressof(get_region(v)), + {v.location(), "while inserting this array-of-tables"} }), v.location()); } @@ -1306,18 +1288,21 @@ insert_nested_key(typename Value::table_type& root, const Value& v, // that points to the key of the table (e.g. [[a]]). By // comparing the first two letters in key, we can detect // the array-of-table is inline or multiline. - if(detail::get_region(a.front()).str().substr(0,2) != "[[") + if(const auto ptr = detail::get_region(a.front())) { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: array of table (\"", - format_dotted_keys(first, last), "\") collides with" - " existing array-of-tables"), { - {std::addressof(get_region(tab->at(k))), - concat_to_string("this ", tab->at(k).type(), - " value has static size")}, - {std::addressof(get_region(v)), - "appending it to the statically sized array"} - }), v.location()); + if(ptr->str().substr(0,2) != "[[") + { + throw syntax_error(format_underline(concat_to_string( + "toml::insert_value: array of table (\"", + format_dotted_keys(first, last), "\") collides " + "with existing array-of-tables"), { + {tab->at(k).location(), + concat_to_string("this ", tab->at(k).type(), + " value has static size")}, + {v.location(), + "appending it to the statically sized array"} + }), v.location()); + } } a.push_back(v); return ok(true); @@ -1341,10 +1326,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: table (\"", format_dotted_keys(first, last), "\") already exists."), { - {std::addressof(get_region(tab->at(k))), - "table already exists here"}, - {std::addressof(get_region(v)), - "table defined twice"} + {tab->at(k).location(), "table already exists here"}, + {v.location(), "table defined twice"} }), v.location()); } // to allow the following toml file. @@ -1368,10 +1351,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, throw syntax_error(format_underline(concat_to_string( "toml::insert_value: array of tables (\"", format_dotted_keys(first, last), "\") already exists."), { - {std::addressof(get_region(tab->at(k))), - "array of tables defined here"}, - {std::addressof(get_region(v)), - "table conflicts with the previous array of table"} + {tab->at(k).location(), "array of tables defined here"}, + {v.location(), "table conflicts with the previous array of table"} }), v.location()); } else @@ -1379,10 +1360,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, throw syntax_error(format_underline(concat_to_string( "toml::insert_value: value (\"", format_dotted_keys(first, last), "\") already exists."), { - {std::addressof(get_region(tab->at(k))), - "value already exists here"}, - {std::addressof(get_region(v)), - "value defined twice"} + {tab->at(k).location(), "value already exists here"}, + {v.location(), "value defined twice"} }), v.location()); } } @@ -1408,18 +1387,18 @@ insert_nested_key(typename Value::table_type& root, const Value& v, // According to toml-lang/toml:36d3091b3 "Clarify that inline // tables are immutable", check if it adds key-value pair to an // inline table. + if(const auto* ptr = get_region(tab->at(k))) { // here, if the value is a (multi-line) table, the region // should be something like `[table-name]`. - if(get_region(tab->at(k)).front() == '{') + if(ptr->front() == '{') { throw syntax_error(format_underline(concat_to_string( "toml::insert_value: inserting to an inline table (", format_dotted_keys(first, std::next(iter)), ") but inline tables are immutable"), { - {std::addressof(get_region(tab->at(k))), - "inline tables are immutable"}, - {std::addressof(get_region(v)), "inserting this"} + {tab->at(k).location(), "inline tables are immutable"}, + {v.location(), "inserting this"} }), v.location()); } } @@ -1434,9 +1413,9 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: target (", format_dotted_keys(first, std::next(iter)), ") is neither table nor an array of tables"), { - {std::addressof(get_region(a.back())), - concat_to_string("actual type is ", a.back().type())}, - {std::addressof(get_region(v)), "inserting this"} + {a.back().location(), concat_to_string( + "actual type is ", a.back().type())}, + {v.location(), "inserting this"} }), v.location()); } tab = std::addressof(a.back().as_table()); @@ -1447,9 +1426,9 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: target (", format_dotted_keys(first, std::next(iter)), ") is neither table nor an array of tables"), { - {std::addressof(get_region(tab->at(k))), - concat_to_string("actual type is ", tab->at(k).type())}, - {std::addressof(get_region(v)), "inserting this"} + {tab->at(k).location(), concat_to_string( + "actual type is ", tab->at(k).type())}, + {v.location(), "inserting this"} }), v.location()); } } @@ -1457,9 +1436,9 @@ insert_nested_key(typename Value::table_type& root, const Value& v, return err(std::string("toml::detail::insert_nested_key: never reach here")); } -template -result>, std::string> -parse_inline_table(location& loc) +template +result, std::string> +parse_inline_table(location& loc) { using value_type = Value; using table_type = typename value_type::table_type; @@ -1469,7 +1448,7 @@ parse_inline_table(location& loc) if(!(loc.iter() != loc.end() && *loc.iter() == '{')) { return err(format_underline("toml::parse_inline_table: ", - {{std::addressof(loc), "the next token is not an inline table"}})); + {{source_location(loc), "the next token is not an inline table"}})); } loc.advance(); // it starts from "{". it should be formatted as inline-table @@ -1479,8 +1458,8 @@ parse_inline_table(location& loc) if(loc.iter() != loc.end() && *loc.iter() == '}') { loc.advance(); // skip `}` - return ok(std::make_pair( - retval, region(loc, first, loc.iter()))); + return ok(std::make_pair(retval, + region(loc, first, loc.iter()))); } const auto kv_r = parse_key_value_pair(loc); @@ -1490,7 +1469,7 @@ parse_inline_table(location& loc) } const auto& kvpair = kv_r.unwrap(); const std::vector& keys = kvpair.first.first; - const region& key_reg = kvpair.first.second; + const auto& key_reg = kvpair.first.second; const value_type& val = kvpair.second; const auto inserted = @@ -1499,7 +1478,7 @@ parse_inline_table(location& loc) { throw internal_error("toml::parse_inline_table: " "failed to insert value into table: " + inserted.unwrap_err(), - source_location(std::addressof(loc))); + source_location(loc)); } using lex_table_separator = sequence, character<','>>; @@ -1511,33 +1490,32 @@ parse_inline_table(location& loc) { loc.advance(); // skip `}` return ok(std::make_pair( - retval, region(loc, first, loc.iter()))); + retval, region(loc, first, loc.iter()))); } else if(*loc.iter() == '#' || *loc.iter() == '\r' || *loc.iter() == '\n') { throw syntax_error(format_underline( "toml::parse_inline_table: missing curly brace `}`", - {{std::addressof(loc), "should be `}`"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "should be `}`"}}), + source_location(loc)); } else { throw syntax_error(format_underline( "toml::parse_inline_table: missing table separator `,` ", - {{std::addressof(loc), "should be `,`"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "should be `,`"}}), + source_location(loc)); } } } loc.reset(first); throw syntax_error(format_underline("toml::parse_inline_table: " "inline table did not closed by `}`", - {{std::addressof(loc), "should be closed"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "should be closed"}}), + source_location(loc)); } -template -result guess_number_type(const location& l) +inline result guess_number_type(const location& l) { // This function tries to find some (common) mistakes by checking characters // that follows the last character of a value. But it is often difficult @@ -1545,7 +1523,7 @@ result guess_number_type(const location& l) // spaces, tabs, commas (in an array or inline table), closing brackets // (of an array or inline table), comment-sign (#). Since this function // does not parse further, those characters are always allowed to be there. - location loc = l; + location loc = l; if(lex_offset_date_time::invoke(loc)) {return ok(value_t::offset_datetime);} loc.reset(l.iter()); @@ -1557,7 +1535,7 @@ result guess_number_type(const location& l) || *loc.iter() == 'Z' || *loc.iter() == 'z')) { return err(format_underline("bad offset: should be [+-]HH:MM or Z", - {{std::addressof(loc), "[+-]HH:MM or Z"}}, + {{source_location(loc), "[+-]HH:MM or Z"}}, {"pass: +09:00, -05:30", "fail: +9:00, -5:30"})); } return ok(value_t::local_datetime); @@ -1577,14 +1555,14 @@ result guess_number_type(const location& l) if(c == 'T' || c == 't') { return err(format_underline("bad time: should be HH:MM:SS.subsec", - {{std::addressof(loc), "HH:MM:SS.subsec"}}, + {{source_location(loc), "HH:MM:SS.subsec"}}, {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", "fail: 1979-05-27T7:32:00, 1979-05-27 17:32"})); } if('0' <= c && c <= '9') { return err(format_underline("bad time: missing T", - {{std::addressof(loc), "T or space required here"}}, + {{source_location(loc), "T or space required here"}}, {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"})); } @@ -1593,7 +1571,7 @@ result guess_number_type(const location& l) { loc.advance(); return err(format_underline("bad time: should be HH:MM:SS.subsec", - {{std::addressof(loc), "HH:MM:SS.subsec"}}, + {{source_location(loc), "HH:MM:SS.subsec"}}, {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"})); } @@ -1610,7 +1588,7 @@ result guess_number_type(const location& l) if(loc.iter() != loc.end() && *loc.iter() == '_') { return err(format_underline("bad float: `_` should be surrounded by digits", - {{std::addressof(loc), "here"}}, + {{source_location(loc), "here"}}, {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); } @@ -1626,7 +1604,7 @@ result guess_number_type(const location& l) if(c == '_') { return err(format_underline("bad integer: `_` should be surrounded by digits", - {{std::addressof(loc), "here"}}, + {{source_location(loc), "here"}}, {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", "fail: 1__000, 0123"})); } @@ -1635,21 +1613,21 @@ result guess_number_type(const location& l) // leading zero. point '0' loc.retrace(); return err(format_underline("bad integer: leading zero", - {{std::addressof(loc), "here"}}, + {{source_location(loc), "here"}}, {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", "fail: 1__000, 0123"})); } if(c == ':' || c == '-') { return err(format_underline("bad datetime: invalid format", - {{std::addressof(loc), "here"}}, + {{source_location(loc), "here"}}, {"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z", "fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"})); } if(c == '.' || c == 'e' || c == 'E') { return err(format_underline("bad float: invalid format", - {{std::addressof(loc), "here"}}, + {{source_location(loc), "here"}}, {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); } @@ -1659,23 +1637,22 @@ result guess_number_type(const location& l) if(loc.iter() != loc.end() && *loc.iter() == '.') { return err(format_underline("bad float: invalid format", - {{std::addressof(loc), "integer part required before this"}}, + {{source_location(loc), "integer part required before this"}}, {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); } if(loc.iter() != loc.end() && *loc.iter() == '_') { return err(format_underline("bad number: `_` should be surrounded by digits", - {{std::addressof(loc), "`_` is not surrounded by digits"}}, + {{source_location(loc), "`_` is not surrounded by digits"}}, {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", "fail: 1__000, 0123"})); } return err(format_underline("bad format: unknown value appeared", - {{std::addressof(loc), "here"}})); + {{source_location(loc), "here"}})); } -template -result guess_value_type(const location& loc) +inline result guess_value_type(const location& loc) { switch(*loc.iter()) { @@ -1691,8 +1668,8 @@ result guess_value_type(const location& loc) } } -template -result parse_value(location& loc) +template +result parse_value(location& loc) { using value_type = Value; @@ -1700,7 +1677,7 @@ result parse_value(location& loc) if(first == loc.end()) { return err(format_underline("toml::parse_value: input is empty", - {{std::addressof(loc), ""}})); + {{source_location(loc), ""}})); } const auto type = guess_value_type(loc); @@ -1723,28 +1700,27 @@ result parse_value(location& loc) default: { const auto msg = format_underline("toml::parse_value: " - "unknown token appeared", {{std::addressof(loc), "unknown"}}); + "unknown token appeared", {{source_location(loc), "unknown"}}); loc.reset(first); return err(msg); } } } -template -result, region>, std::string> -parse_table_key(location& loc) +inline result, region>, std::string> +parse_table_key(location& loc) { if(auto token = lex_std_table::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto open = lex_std_table_open::invoke(inner_loc); if(!open || inner_loc.iter() == inner_loc.end()) { throw internal_error(format_underline( "toml::parse_table_key: no `[`", - {{std::addressof(inner_loc), "should be `[`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `[`"}}), + source_location(inner_loc)); } // to skip [ a . b . c ] // ^----------- this whitespace @@ -1754,8 +1730,8 @@ parse_table_key(location& loc) { throw internal_error(format_underline( "toml::parse_table_key: invalid key", - {{std::addressof(inner_loc), "not key"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "not key"}}), + source_location(inner_loc)); } // to skip [ a . b . c ] // ^-- this whitespace @@ -1765,8 +1741,8 @@ parse_table_key(location& loc) { throw internal_error(format_underline( "toml::parse_table_key: no `]`", - {{std::addressof(inner_loc), "should be `]`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `]`"}}), + source_location(inner_loc)); } // after [table.key], newline or EOF(empty table) requried. @@ -1779,8 +1755,8 @@ parse_table_key(location& loc) { throw syntax_error(format_underline( "toml::parse_table_key: newline required after [table.key]", - {{std::addressof(loc), "expected newline"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "expected newline"}}), + source_location(loc)); } } return ok(std::make_pair(keys.unwrap().first, token.unwrap())); @@ -1788,25 +1764,24 @@ parse_table_key(location& loc) else { return err(format_underline("toml::parse_table_key: " - "not a valid table key", {{std::addressof(loc), "here"}})); + "not a valid table key", {{source_location(loc), "here"}})); } } -template -result, region>, std::string> -parse_array_table_key(location& loc) +inline result, region>, std::string> +parse_array_table_key(location& loc) { if(auto token = lex_array_table::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); const auto open = lex_array_table_open::invoke(inner_loc); if(!open || inner_loc.iter() == inner_loc.end()) { throw internal_error(format_underline( "toml::parse_array_table_key: no `[[`", - {{std::addressof(inner_loc), "should be `[[`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `[[`"}}), + source_location(inner_loc)); } lex_ws::invoke(inner_loc); const auto keys = parse_key(inner_loc); @@ -1814,8 +1789,8 @@ parse_array_table_key(location& loc) { throw internal_error(format_underline( "toml::parse_array_table_key: invalid key", - {{std::addressof(inner_loc), "not a key"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "not a key"}}), + source_location(inner_loc)); } lex_ws::invoke(inner_loc); const auto close = lex_array_table_close::invoke(inner_loc); @@ -1823,8 +1798,8 @@ parse_array_table_key(location& loc) { throw internal_error(format_underline( "toml::parse_table_key: no `]]`", - {{std::addressof(inner_loc), "should be `]]`"}}), - source_location(std::addressof(inner_loc))); + {{source_location(inner_loc), "should be `]]`"}}), + source_location(inner_loc)); } // after [[table.key]], newline or EOF(empty table) requried. @@ -1837,8 +1812,8 @@ parse_array_table_key(location& loc) { throw syntax_error(format_underline("toml::" "parse_array_table_key: newline required after [[table.key]]", - {{std::addressof(loc), "expected newline"}}), - source_location(std::addressof(loc))); + {{source_location(loc), "expected newline"}}), + source_location(loc)); } } return ok(std::make_pair(keys.unwrap().first, token.unwrap())); @@ -1846,14 +1821,14 @@ parse_array_table_key(location& loc) else { return err(format_underline("toml::parse_array_table_key: " - "not a valid table key", {{std::addressof(loc), "here"}})); + "not a valid table key", {{source_location(loc), "here"}})); } } // parse table body (key-value pairs until the iter hits the next [tablekey]) -template +template result -parse_ml_table(location& loc) +parse_ml_table(location& loc) { using value_type = Value; using table_type = typename value_type::table_type; @@ -1890,7 +1865,7 @@ parse_ml_table(location& loc) { const auto& kvpair = kv.unwrap(); const std::vector& keys = kvpair.first.first; - const region& key_reg = kvpair.first.second; + const auto& key_reg = kvpair.first.second; const value_type& val = kvpair.second; const auto inserted = insert_nested_key(tab, val, keys.begin(), keys.end(), key_reg); @@ -1921,7 +1896,7 @@ parse_ml_table(location& loc) const auto before2 = loc.iter(); lex_ws::invoke(loc); // skip whitespace const auto msg = format_underline("toml::parse_table: " - "invalid line format", {{std::addressof(loc), concat_to_string( + "invalid line format", {{source_location(loc), concat_to_string( "expected newline, but got '", show_char(*loc.iter()), "'.")}}); loc.reset(before2); return err(msg); @@ -1936,8 +1911,8 @@ parse_ml_table(location& loc) return ok(tab); } -template -result parse_toml_file(location& loc) +template +result parse_toml_file(location& loc) { using value_type = Value; using table_type = typename value_type::table_type; @@ -1950,7 +1925,7 @@ result parse_toml_file(location& loc) // put the first line as a region of a file // Here first != loc.end(), so taking std::next is okay - const region file(loc, first, std::next(loc.iter())); + const region file(loc, first, std::next(loc.iter())); // The first successive comments that are separated from the first value // by an empty line are for a file itself. @@ -1970,7 +1945,7 @@ result parse_toml_file(location& loc) >; if(const auto token = lex_first_comments::invoke(loc)) { - location inner_loc(loc.name(), token.unwrap().str()); + location inner_loc(loc.name(), token.unwrap().str()); while(inner_loc.iter() != inner_loc.end()) { maybe::invoke(inner_loc); // remove ws if exists @@ -2035,7 +2010,7 @@ result parse_toml_file(location& loc) continue; } return err(format_underline("toml::parse_toml_file: " - "unknown line appeared", {{std::addressof(loc), "unknown format"}})); + "unknown line appeared", {{source_location(loc), "unknown format"}})); } Value v(std::move(data), file); @@ -2071,8 +2046,7 @@ parse(std::istream& is, const std::string& fname = "unknown file") } assert(letters.empty() || letters.back() != '\0'); - detail::location> - loc(std::move(fname), std::move(letters)); + detail::location loc(std::move(fname), std::move(letters)); // skip BOM if exists. // XXX component of BOM (like 0xEF) exceeds the representable range of @@ -2093,7 +2067,7 @@ parse(std::istream& is, const std::string& fname = "unknown file") const auto data = detail::parse_toml_file(loc); if(!data) { - throw syntax_error(data.unwrap_err(), source_location(std::addressof(loc))); + throw syntax_error(data.unwrap_err(), source_location(loc)); } return data.unwrap(); } diff --git a/toml/region.hpp b/toml/region.hpp index c87547a..6761aed 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -67,22 +67,21 @@ struct region_base // // it contains pointer to the file content and iterator that points the current // location. -template struct location final : public region_base { - using const_iterator = typename Container::const_iterator; + using const_iterator = typename std::vector::const_iterator; using difference_type = typename const_iterator::difference_type; - using source_ptr = std::shared_ptr; + using source_ptr = std::shared_ptr>; - static_assert(std::is_same::value,""); - static_assert(std::is_same::iterator_category>::value, - "container should be randomly accessible"); - - location(std::string name, Container cont) - : source_(std::make_shared(std::move(cont))), line_number_(1), - source_name_(std::move(name)), iter_(source_->cbegin()) + location(std::string name, std::vector cont) + : source_(std::make_shared>(std::move(cont))), + line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin()) {} + location(std::string name, const std::string& cont) + : source_(std::make_shared>(cont.begin(), cont.end())), + line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin()) + {} + location(const location&) = default; location(location&&) = default; location& operator=(const location&) = default; @@ -195,33 +194,27 @@ struct location final : public region_base // // it contains pointer to the file content and iterator that points the first // and last location. -template struct region final : public region_base { - using const_iterator = typename Container::const_iterator; - using source_ptr = std::shared_ptr; - - static_assert(std::is_same::value,""); - static_assert(std::is_same::iterator_category>::value, - "container should be randomly accessible"); + using const_iterator = typename std::vector::const_iterator; + using source_ptr = std::shared_ptr>; // delete default constructor. source_ never be null. region() = delete; - region(const location& loc) + explicit region(const location& loc) : source_(loc.source()), source_name_(loc.name()), first_(loc.iter()), last_(loc.iter()) {} - region(location&& loc) + explicit region(location&& loc) : source_(loc.source()), source_name_(loc.name()), first_(loc.iter()), last_(loc.iter()) {} - region(const location& loc, const_iterator f, const_iterator l) + region(const location& loc, const_iterator f, const_iterator l) : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l) {} - region(location&& loc, const_iterator f, const_iterator l) + region(location&& loc, const_iterator f, const_iterator l) : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l) {} @@ -419,107 +412,6 @@ struct region final : public region_base const_iterator first_, last_; }; -// to show a better error message. -inline std::string format_underline(const std::string& message, - const std::vector>& reg_com, - const std::vector& helps = {}, - const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) -{ - assert(!reg_com.empty()); - - const auto line_num_width = static_cast(std::max_element( - reg_com.begin(), reg_com.end(), - [](std::pair const& lhs, - std::pair const& rhs) - { - return lhs.first->line_num().size() < rhs.first->line_num().size(); - } - )->first->line_num().size()); - - std::ostringstream retval; - - if(colorize) - { - retval << color::colorize; // turn on ANSI color - } - - // XXX - // Here, before `colorize` support, it does not output `[error]` prefix - // automatically. So some user may output it manually and this change may - // duplicate the prefix. To avoid it, check the first 7 characters and - // if it is "[error]", it removes that part from the message shown. - if(message.size() > 7 && message.substr(0, 7) == "[error]") - { - retval << color::bold << color::red << "[error]" << color::reset - << color::bold << message.substr(7) << color::reset << '\n'; - } - else - { - retval << color::bold << color::red << "[error] " << color::reset - << color::bold << message << color::reset << '\n'; - } - - for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter) - { - // if the filenames are the same, print "..." - if(iter != reg_com.begin() && - std::prev(iter)->first->name() == iter->first->name()) - { - retval << color::bold << color::blue << "\n ...\n" << color::reset; - } - else // if filename differs, print " --> filename.toml" - { - if(iter != reg_com.begin()) {retval << '\n';} - retval << color::bold << color::blue << " --> " << color::reset - << iter->first->name() << '\n'; - // add one almost-empty line for readability - retval << make_string(static_cast(line_num_width + 1), ' ') - << color::bold << color::blue << " | " << color::reset << '\n'; - } - const region_base* const reg = iter->first; - const std::string& comment = iter->second; - - retval << ' ' << color::bold << color::blue << std::setw(line_num_width) - << std::right << reg->line_num() << " | " << color::reset - << reg->line() << '\n'; - - retval << make_string(static_cast(line_num_width + 1), ' ') - << color::bold << color::blue << " | " << color::reset - << make_string(reg->before(), ' '); - - if(reg->size() == 1) - { - // invalid - // ^------ - retval << color::bold << color::red - << '^' << make_string(reg->after(), '-') << color::reset; - } - else - { - // invalid - // ~~~~~~~ - const auto underline_len = (std::min)(reg->size(), reg->line().size()); - retval << color::bold << color::red - << make_string(underline_len, '~') << color::reset; - } - retval << ' '; - retval << comment; - } - - if(!helps.empty()) - { - retval << '\n'; - retval << make_string(static_cast(line_num_width + 1), ' '); - retval << color::bold << color::blue << " | " << color::reset; - for(const auto& help : helps) - { - retval << color::bold << "\nHint: " << color::reset; - retval << help; - } - } - return retval.str(); -} - } // detail } // toml #endif// TOML11_REGION_H diff --git a/toml/serializer.hpp b/toml/serializer.hpp index 4ed929a..ed07f46 100644 --- a/toml/serializer.hpp +++ b/toml/serializer.hpp @@ -29,7 +29,7 @@ std::basic_string format_key(const std::basic_string& key) { // check the key can be a bare (unquoted) key - detail::location loc(key, key); + detail::location loc(key, std::vector(key.begin(), key.end())); detail::lex_unquoted_key::invoke(loc); if(loc.iter() == loc.end()) { diff --git a/toml/source_location.hpp b/toml/source_location.hpp index 8c14b96..26ff216 100644 --- a/toml/source_location.hpp +++ b/toml/source_location.hpp @@ -61,6 +61,21 @@ struct source_location } } + explicit source_location(const detail::region& reg) + : line_num_(static_cast(std::stoul(reg.line_num()))), + column_num_(static_cast(reg.before() + 1)), + region_size_(static_cast(reg.size())), + file_name_(reg.name()), + line_str_ (reg.line()) + {} + explicit source_location(const detail::location& loc) + : line_num_(static_cast(std::stoul(loc.line_num()))), + column_num_(static_cast(loc.before() + 1)), + region_size_(static_cast(loc.size())), + file_name_(loc.name()), + line_str_ (loc.line()) + {} + ~source_location() = default; source_location(source_location const&) = default; source_location(source_location &&) = default; @@ -83,5 +98,135 @@ struct source_location std::string line_str_; }; +namespace detail +{ + +// internal error message generation. +inline std::string format_underline(const std::string& message, + const std::vector>& loc_com, + const std::vector& helps = {}, + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) +{ + std::size_t line_num_width = 0; + for(const auto& lc : loc_com) + { + std::uint_least32_t line = lc.first.line(); + std::size_t digit = 0; + while(line != 0) + { + line /= 10; + digit += 1; + } + line_num_width = (std::max)(line_num_width, digit); + } + // 1 is the minimum width + line_num_width = std::max(line_num_width, 1); + + std::ostringstream retval; + + if(colorize) + { + retval << color::colorize; // turn on ANSI color + } + + // XXX + // Here, before `colorize` support, it does not output `[error]` prefix + // automatically. So some user may output it manually and this change may + // duplicate the prefix. To avoid it, check the first 7 characters and + // if it is "[error]", it removes that part from the message shown. + if(message.size() > 7 && message.substr(0, 7) == "[error]") + { + retval << color::bold << color::red << "[error]" << color::reset + << color::bold << message.substr(7) << color::reset << '\n'; + } + else + { + retval << color::bold << color::red << "[error] " << color::reset + << color::bold << message << color::reset << '\n'; + } + + const auto format_one_location = [line_num_width] + (std::ostringstream& oss, + const source_location& loc, const std::string& comment) -> void + { + oss << ' ' << color::bold << color::blue + << std::setw(static_cast(line_num_width)) + << std::right << loc.line() << " | " << color::reset + << loc.line_str() << '\n'; + + oss << make_string(line_num_width + 1, ' ') + << color::bold << color::blue << " | " << color::reset + << make_string(loc.column()-1 /*1-origin*/, ' '); + + if(loc.region() == 1) + { + // invalid + // ^------ + oss << color::bold << color::red << "^---" << color::reset; + } + else + { + // invalid + // ~~~~~~~ + const auto underline_len = (std::min)( + static_cast(loc.region()), loc.line_str().size()); + oss << color::bold << color::red + << make_string(underline_len, '~') << color::reset; + } + oss << ' '; + oss << comment; + return; + }; + + assert(!loc_com.empty()); + + // --> example.toml + // | + retval << color::bold << color::blue << " --> " << color::reset + << loc_com.front().first.file_name() << '\n'; + retval << make_string(line_num_width + 1, ' ') + << color::bold << color::blue << " | " << color::reset << '\n'; + // 1 | key value + // | ^--- missing = + format_one_location(retval, loc_com.front().first, loc_com.front().second); + + // process the rest of the locations + for(std::size_t i=1; i filename.toml" again + { + retval << color::bold << color::blue << " --> " << color::reset + << curr.first.file_name() << '\n'; + retval << make_string(line_num_width + 1, ' ') + << color::bold << color::blue << " |\n" << color::reset; + } + + format_one_location(retval, curr.first, curr.second); + } + + if(!helps.empty()) + { + retval << '\n'; + retval << make_string(line_num_width + 1, ' '); + retval << color::bold << color::blue << " | " << color::reset; + for(const auto& help : helps) + { + retval << color::bold << "\nHint: " << color::reset; + retval << help; + } + } + return retval.str(); +} + +} // detail } // toml #endif// TOML11_SOURCE_LOCATION_HPP diff --git a/toml/value.hpp b/toml/value.hpp index d2f8cb9..76eee0d 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -22,21 +22,15 @@ namespace detail // to show error messages. not recommended for users. template -inline region_base const& get_region(const Value& v) +inline region_base const* get_region(const Value& v) { - return *(v.region_info_); + return v.region_info_.get(); } -template -void change_region(Value& v, Region&& reg) +template +void change_region(Value& v, region reg) { - using region_type = typename std::remove_reference< - typename std::remove_cv::type - >::type; - - std::shared_ptr new_reg = - std::make_shared(std::forward(reg)); - v.region_info_ = new_reg; + v.region_info_ = std::make_shared(std::move(reg)); return; } @@ -46,8 +40,7 @@ throw_bad_cast(const std::string& funcname, value_t actual, const Value& v) { throw type_error(detail::format_underline( concat_to_string(funcname, "bad_cast to ", Expected), { - {std::addressof(get_region(v)), - concat_to_string("the actual type is ", actual)} + {v.location(), concat_to_string("the actual type is ", actual)} }), v.location()); } @@ -74,8 +67,8 @@ throw_key_not_found_error(const Value& v, const key& ky) // It actually points to the top-level table at the first character, // not `[table]`. But it is too confusing. To avoid the confusion, the error // message should explicitly say "key not found in the top-level table". - const auto& reg = get_region(v); - if(reg.line_num() == "1" && reg.size() == 1) + const auto loc = v.location(); + if(loc.line() == 1 && loc.region() == 1) { // Here it assumes that top-level table starts at the first character. // The region corresponds to the top-level table will be generated at @@ -111,16 +104,14 @@ throw_key_not_found_error(const Value& v, const key& ky) // throw std::out_of_range(format_underline(concat_to_string( "key \"", ky, "\" not found in the top-level table"), { - {std::addressof(reg), "the top-level table starts here"} + {loc, "the top-level table starts here"} })); } else { // normal table. throw std::out_of_range(format_underline(concat_to_string( - "key \"", ky, "\" not found"), { - {std::addressof(reg), "in this table"} - })); + "key \"", ky, "\" not found"), { {loc, "in this table"} })); } } @@ -1056,95 +1047,87 @@ class basic_value // // Those constructors take detail::region that contains parse result. - template - basic_value(boolean b, detail::region reg) + basic_value(boolean b, detail::region reg) : type_(value_t::boolean), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->boolean_, b); } - template, detail::negation> >::value, std::nullptr_t>::type = nullptr> - basic_value(T i, detail::region reg) + basic_value(T i, detail::region reg) : type_(value_t::integer), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->integer_, static_cast(i)); } - template::value, std::nullptr_t>::type = nullptr> - basic_value(T f, detail::region reg) + basic_value(T f, detail::region reg) : type_(value_t::floating), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->floating_, static_cast(f)); } - template - basic_value(toml::string s, detail::region reg) + basic_value(toml::string s, detail::region reg) : type_(value_t::string), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->string_, std::move(s)); } - template - basic_value(const local_date& ld, detail::region reg) + basic_value(const local_date& ld, detail::region reg) : type_(value_t::local_date), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->local_date_, ld); } - template - basic_value(const local_time& lt, detail::region reg) + basic_value(const local_time& lt, detail::region reg) : type_(value_t::local_time), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->local_time_, lt); } - template - basic_value(const local_datetime& ldt, detail::region reg) + basic_value(const local_datetime& ldt, detail::region reg) : type_(value_t::local_datetime), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->local_datetime_, ldt); } - template - basic_value(const offset_datetime& odt, detail::region reg) + basic_value(const offset_datetime& odt, detail::region reg) : type_(value_t::offset_datetime), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->offset_datetime_, odt); } - template - basic_value(const array_type& ary, detail::region reg) + basic_value(const array_type& ary, detail::region reg) : type_(value_t::array), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->array_, ary); } - template - basic_value(const table_type& tab, detail::region reg) + basic_value(const table_type& tab, detail::region reg) : type_(value_t::table), - region_info_(std::make_shared>(std::move(reg))), + region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->table_, tab); } - template::value, std::nullptr_t>::type = nullptr> - basic_value(std::pair> parse_result) + basic_value(std::pair parse_result) : basic_value(std::move(parse_result.first), std::move(parse_result.second)) {} @@ -1578,9 +1561,9 @@ class basic_value { throw std::out_of_range(detail::format_underline( "toml::value::at(idx): no element corresponding to the index", { - {this->region_info_.get(), - concat_to_string("the length is ", this->as_array(std::nothrow).size(), - ", and the specified index is ", idx)} + {this->location(), concat_to_string("the length is ", + this->as_array(std::nothrow).size(), + ", and the specified index is ", idx)} })); } return this->as_array().at(idx); @@ -1596,9 +1579,9 @@ class basic_value { throw std::out_of_range(detail::format_underline( "toml::value::at(idx): no element corresponding to the index", { - {this->region_info_.get(), - concat_to_string("the length is ", this->as_array(std::nothrow).size(), - ", and the specified index is ", idx)} + {this->location(), concat_to_string("the length is ", + this->as_array(std::nothrow).size(), + ", and the specified index is ", idx)} })); } return this->as_array(std::nothrow).at(idx); @@ -1668,7 +1651,7 @@ class basic_value { throw type_error(detail::format_underline( "toml::value::size(): bad_cast to container types", { - {this->region_info_.get(), + {this->location(), concat_to_string("the actual type is ", this->type_)} }), this->location()); } @@ -1718,10 +1701,10 @@ class basic_value // for error messages template - friend region_base const& detail::get_region(const Value& v); + friend region_base const* detail::get_region(const Value& v); - template - friend void detail::change_region(Value& v, Region&& reg); + template + friend void detail::change_region(Value& v, detail::region reg); private: @@ -1926,10 +1909,8 @@ inline std::string format_error(const std::string& err_msg, std::vector hints = {}, const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { - return detail::format_underline(err_msg, - std::vector>{ - {std::addressof(detail::get_region(v)), comment} - }, std::move(hints), colorize); + return detail::format_underline(err_msg, {{v.location(), comment}}, + std::move(hints), colorize); } template class T, template class A> @@ -1939,10 +1920,8 @@ inline std::string format_error(const std::string& err_msg, std::vector hints = {}, const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { - return detail::format_underline(err_msg, - std::vector>{ - {std::addressof(detail::get_region(v1)), comment1}, - {std::addressof(detail::get_region(v2)), comment2} + return detail::format_underline(err_msg, { + {v1.location(), comment1}, {v2.location(), comment2} }, std::move(hints), colorize); } @@ -1954,11 +1933,8 @@ inline std::string format_error(const std::string& err_msg, std::vector hints = {}, const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { - return detail::format_underline(err_msg, - std::vector>{ - {std::addressof(detail::get_region(v1)), comment1}, - {std::addressof(detail::get_region(v2)), comment2}, - {std::addressof(detail::get_region(v3)), comment3} + return detail::format_underline(err_msg, {{v1.location(), comment1}, + {v2.location(), comment2}, {v3.location(), comment3} }, std::move(hints), colorize); }