From b461f363daf7f7b56cde6a77a29b7c8138c91957 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 20 Jul 2020 19:40:55 +0900 Subject: [PATCH 01/16] refactor: add a method to reduce complexity later --- toml/region.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toml/region.hpp b/toml/region.hpp index c87547a..ee33c93 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -48,6 +48,8 @@ struct region_base virtual std::string line() const {return std::string("unknown line");} virtual std::string line_num() const {return std::string("?");} + virtual std::vector vec() const {return std::vector{};} + // length of the region virtual std::size_t size() const noexcept {return 0;} // number of characters in the line before the region @@ -141,6 +143,8 @@ struct location final : public region_base std::string str() const override {return make_string(1, *this->iter());} std::string name() const override {return source_name_;} + std::vector vec() const override {return std::vector{*this->iter()};} + std::string line_num() const override { return std::to_string(this->line_number_); @@ -259,6 +263,8 @@ struct region final : public region_base return std::to_string(1 + std::count(this->begin(), this->first(), '\n')); } + std::vector vec() const override {return std::vector(first_, last_);} + std::size_t size() const noexcept override { const auto sz = std::distance(first_, last_); From 259da54edb5c433d2a30813bddcf05425c8e681b Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 20 Jul 2020 19:52:11 +0900 Subject: [PATCH 02/16] refactor: always use vector in location `location` and `region` have a (shared_ptr to the) container of TOML contents. Those take a template argument to allow both std::vector and std::string as an interanal container. But since those are internal feature, i.e. it should not be used by a user directly, this template can be removed by re-writing a parser a bit. This introduces a complexity to toml11 error reporting system, so I'm removing this. First, remove all the location from the parser. Then the template argument can be removed because everyone uses std::vector now. --- toml/parser.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 586a0fd..333f3d1 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -510,7 +510,7 @@ 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().vec()); const auto open = lex_ml_literal_string_open::invoke(inner_loc); if(!open) @@ -573,7 +573,7 @@ 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().vec()); const auto open = lex_apostrophe::invoke(inner_loc); if(!open) @@ -646,7 +646,7 @@ 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().vec()); const auto y = lex_date_fullyear::invoke(inner_loc); if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') @@ -696,7 +696,7 @@ 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().vec()); const auto h = lex_time_hour::invoke(inner_loc); if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') @@ -785,7 +785,7 @@ 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().vec()); const auto date = parse_local_date(inner_loc); if(!date || inner_loc.iter() == inner_loc.end()) { @@ -830,7 +830,7 @@ 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().vec()); const auto datetime = parse_local_datetime(inner_loc); if(!datetime || inner_loc.iter() == inner_loc.end()) { @@ -903,7 +903,7 @@ parse_key(location& loc) 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.vec()); std::vector keys; while(inner_loc.iter() != inner_loc.end()) @@ -1182,7 +1182,7 @@ 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()); + location> def("internal", detail::get_region(fwd).vec()); if(const auto tabkeys = parse_table_key(def)) { // table keys always contains all the nodes from the root. @@ -1736,7 +1736,7 @@ 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().vec()); const auto open = lex_std_table_open::invoke(inner_loc); if(!open || inner_loc.iter() == inner_loc.end()) @@ -1798,7 +1798,7 @@ 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().vec()); const auto open = lex_array_table_open::invoke(inner_loc); if(!open || inner_loc.iter() == inner_loc.end()) @@ -1970,7 +1970,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().vec()); while(inner_loc.iter() != inner_loc.end()) { maybe::invoke(inner_loc); // remove ws if exists From 75999aa9ad6d5ee65b799b8eb6d98be866211dfa Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 21 Jul 2020 20:52:39 +0900 Subject: [PATCH 03/16] refactor: add a constructor to location By adding the constructor, vec() would not be not needed. But inserting Container = std::string makes the constructor ambiguous, so it breaks the current code. --- toml/region.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toml/region.hpp b/toml/region.hpp index ee33c93..dd8086c 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -85,6 +85,12 @@ struct location final : public region_base : 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; From a8fa14d15979e7cc3234f5e47b52de3dd55bce22 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 21 Jul 2020 20:55:18 +0900 Subject: [PATCH 04/16] refactor: remove vec() method, use a constructor --- toml/parser.hpp | 22 +++++++++++----------- toml/region.hpp | 6 ------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 333f3d1..fbbf38c 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -510,7 +510,7 @@ 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().vec()); + location> inner_loc(loc.name(), token.unwrap().str()); const auto open = lex_ml_literal_string_open::invoke(inner_loc); if(!open) @@ -573,7 +573,7 @@ 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().vec()); + location> inner_loc(loc.name(), token.unwrap().str()); const auto open = lex_apostrophe::invoke(inner_loc); if(!open) @@ -646,7 +646,7 @@ 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().vec()); + 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() != '-') @@ -696,7 +696,7 @@ 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().vec()); + 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() != ':') @@ -785,7 +785,7 @@ 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().vec()); + location> inner_loc(loc.name(), token.unwrap().str()); const auto date = parse_local_date(inner_loc); if(!date || inner_loc.iter() == inner_loc.end()) { @@ -830,7 +830,7 @@ 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().vec()); + location> inner_loc(loc.name(), token.unwrap().str()); const auto datetime = parse_local_datetime(inner_loc); if(!datetime || inner_loc.iter() == inner_loc.end()) { @@ -903,7 +903,7 @@ parse_key(location& loc) if(const auto token = lex_dotted_key::invoke(loc)) { const auto reg = token.unwrap(); - location> inner_loc(loc.name(), reg.vec()); + location> inner_loc(loc.name(), reg.str()); std::vector keys; while(inner_loc.iter() != inner_loc.end()) @@ -1182,7 +1182,7 @@ 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).vec()); + location> def("internal", detail::get_region(fwd).str()); if(const auto tabkeys = parse_table_key(def)) { // table keys always contains all the nodes from the root. @@ -1736,7 +1736,7 @@ parse_table_key(location& loc) { if(auto token = lex_std_table::invoke(loc)) { - location> inner_loc(loc.name(), token.unwrap().vec()); + 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()) @@ -1798,7 +1798,7 @@ parse_array_table_key(location& loc) { if(auto token = lex_array_table::invoke(loc)) { - location> inner_loc(loc.name(), token.unwrap().vec()); + 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()) @@ -1970,7 +1970,7 @@ result parse_toml_file(location& loc) >; if(const auto token = lex_first_comments::invoke(loc)) { - location> inner_loc(loc.name(), token.unwrap().vec()); + location> inner_loc(loc.name(), token.unwrap().str()); while(inner_loc.iter() != inner_loc.end()) { maybe::invoke(inner_loc); // remove ws if exists diff --git a/toml/region.hpp b/toml/region.hpp index dd8086c..bc5d98c 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -48,8 +48,6 @@ struct region_base virtual std::string line() const {return std::string("unknown line");} virtual std::string line_num() const {return std::string("?");} - virtual std::vector vec() const {return std::vector{};} - // length of the region virtual std::size_t size() const noexcept {return 0;} // number of characters in the line before the region @@ -149,8 +147,6 @@ struct location final : public region_base std::string str() const override {return make_string(1, *this->iter());} std::string name() const override {return source_name_;} - std::vector vec() const override {return std::vector{*this->iter()};} - std::string line_num() const override { return std::to_string(this->line_number_); @@ -269,8 +265,6 @@ struct region final : public region_base return std::to_string(1 + std::count(this->begin(), this->first(), '\n')); } - std::vector vec() const override {return std::vector(first_, last_);} - std::size_t size() const noexcept override { const auto sz = std::distance(first_, last_); From 72f5afb6afc31a1a023941aec365c91600b869b1 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 25 Jul 2020 21:06:26 +0900 Subject: [PATCH 05/16] refactor: remove template from detail::location --- tests/test_lex_aux.hpp | 4 +- tests/test_parse_aux.hpp | 4 +- tests/test_parse_floating.cpp | 12 +-- tests/test_parse_table.cpp | 4 +- toml/combinator.hpp | 96 ++++++----------- toml/literal.hpp | 2 +- toml/parser.hpp | 196 +++++++++++++++------------------- toml/region.hpp | 27 ++--- toml/serializer.hpp | 2 +- 9 files changed, 143 insertions(+), 204 deletions(-) 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..4df55aa 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + 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>, none_t> + invoke(location& loc) { - region retval(loc); + region> retval(loc); while(true) { auto rslt = T::invoke(loc); diff --git a/toml/literal.hpp b/toml/literal.hpp index 14b6883..65a5511 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)); diff --git a/toml/parser.hpp b/toml/parser.hpp index fbbf38c..6ab5252 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)) @@ -48,9 +47,8 @@ parse_boolean(location& loc) {{std::addressof(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)) @@ -78,9 +76,8 @@ parse_binary_integer(location& loc) {{std::addressof(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)) @@ -99,9 +96,8 @@ parse_octal_integer(location& loc) {{std::addressof(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)) @@ -120,9 +116,8 @@ parse_hexadecimal_integer(location& loc) {{std::addressof(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 @@ -166,9 +161,8 @@ parse_integer(location& loc) {{std::addressof(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)) @@ -255,9 +249,9 @@ parse_floating(location& loc) {{std::addressof(loc), "the next token is not a float"}})); } -template +template std::string read_utf8_codepoint(const region& reg, - /* for err msg */ const location& loc) + /* for err msg */ const location& loc) { const auto str = reg.str().substr(1); std::uint_least32_t codepoint; @@ -314,8 +308,7 @@ std::string read_utf8_codepoint(const region& reg, 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 != '\\') @@ -370,9 +363,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)) @@ -450,9 +442,8 @@ parse_ml_basic_string(location& loc) } } -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)) @@ -503,14 +494,13 @@ parse_basic_string(location& loc) } } -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) @@ -566,14 +556,13 @@ parse_ml_literal_string(location& loc) } } -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) @@ -607,9 +596,8 @@ parse_literal_string(location& loc) } } -template -result>, std::string> -parse_string(location& loc) +inline result>>, std::string> +parse_string(location& loc) { if(loc.iter() != loc.end() && *(loc.iter()) == '"') { @@ -639,14 +627,13 @@ parse_string(location& loc) {{std::addressof(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() != '-') @@ -689,14 +676,13 @@ parse_local_date(location& loc) } } -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() != ':') @@ -778,14 +764,13 @@ parse_local_time(location& loc) } } -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()) { @@ -823,14 +808,13 @@ parse_local_datetime(location& loc) } } -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()) { @@ -872,9 +856,8 @@ parse_offset_datetime(location& loc) } } -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)) { @@ -894,16 +877,15 @@ parse_simple_key(location& loc) } // 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()) @@ -953,12 +935,12 @@ parse_key(location& loc) } // 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 +968,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)) @@ -1039,7 +1021,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 { @@ -1061,9 +1043,9 @@ parse_array(location& loc) source_location(std::addressof(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; @@ -1151,9 +1133,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 +1163,7 @@ 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()); + location def("internal", detail::get_region(fwd).str()); if(const auto tabkeys = parse_table_key(def)) { // table keys always contains all the nodes from the root. @@ -1220,11 +1201,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_same -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; @@ -1479,8 +1460,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 +1471,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 = @@ -1511,7 +1492,7 @@ 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') { @@ -1536,8 +1517,7 @@ parse_inline_table(location& loc) source_location(std::addressof(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 +1525,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()); @@ -1674,8 +1654,7 @@ result guess_number_type(const location& l) {{std::addressof(loc), "here"}})); } -template -result guess_value_type(const location& loc) +inline result guess_value_type(const location& loc) { switch(*loc.iter()) { @@ -1691,8 +1670,8 @@ result guess_value_type(const location& loc) } } -template -result parse_value(location& loc) +template +result parse_value(location& loc) { using value_type = Value; @@ -1730,13 +1709,12 @@ result parse_value(location& loc) } } -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()) @@ -1792,13 +1770,12 @@ parse_table_key(location& loc) } } -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()) @@ -1851,9 +1828,9 @@ parse_array_table_key(location& loc) } // 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 +1867,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); @@ -1936,8 +1913,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 +1927,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 +1947,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 @@ -2071,8 +2048,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 diff --git a/toml/region.hpp b/toml/region.hpp index bc5d98c..55a748d 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -67,25 +67,18 @@ 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())), + : source_(std::make_shared>(cont.begin(), cont.end())), line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin()) {} @@ -215,19 +208,19 @@ struct region final : public region_base // delete default constructor. source_ never be null. region() = delete; - region(const location& loc) + region(const location& loc) : source_(loc.source()), source_name_(loc.name()), first_(loc.iter()), last_(loc.iter()) {} - region(location&& loc) + 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) {} 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()) { From 19cc9a2edf11d81203c6cd6c1a085d373c58d975 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 25 Jul 2020 22:01:34 +0900 Subject: [PATCH 06/16] refactor: remove template from detail::region --- toml/combinator.hpp | 42 ++++++++++++++--------------- toml/parser.hpp | 64 ++++++++++++++++++++++----------------------- toml/region.hpp | 10 ++----- toml/value.hpp | 56 +++++++++++++++++---------------------- 4 files changed, 78 insertions(+), 94 deletions(-) diff --git a/toml/combinator.hpp b/toml/combinator.hpp index 4df55aa..e250188 100644 --- a/toml/combinator.hpp +++ b/toml/combinator.hpp @@ -58,7 +58,7 @@ struct character { static constexpr char target = C; - static result>, none_t> + static result invoke(location& loc) { if(loc.iter() == loc.end()) {return none();} @@ -71,7 +71,7 @@ struct character } loc.advance(); // update location - return ok(region>(loc, first, loc.iter())); + return ok(region(loc, first, loc.iter())); } }; template @@ -87,7 +87,7 @@ struct in_range static constexpr char upper = Up; static constexpr char lower = Low; - static result>, none_t> + static result invoke(location& loc) { if(loc.iter() == loc.end()) {return none();} @@ -100,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; @@ -111,7 +111,7 @@ template constexpr char in_range::lower; template struct exclude { - static result>, none_t> + static result invoke(location& loc) { if(loc.iter() == loc.end()) {return none();} @@ -124,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())); } }; @@ -132,7 +132,7 @@ struct exclude template struct maybe { - static result>, none_t> + static result invoke(location& loc) { const auto rslt = Combinator::invoke(loc); @@ -140,7 +140,7 @@ struct maybe { return rslt; } - return ok(region>(loc)); + return ok(region(loc)); } }; @@ -150,7 +150,7 @@ struct sequence; template struct sequence { - static result>, none_t> + static result invoke(location& loc) { const auto first = loc.iter(); @@ -165,8 +165,8 @@ struct sequence // called from the above function only, recursively. template - static result>, none_t> - invoke(location& loc, region> reg, Iterator first) + static result + invoke(location& loc, region reg, Iterator first) { const auto rslt = Head::invoke(loc); if(rslt.is_err()) @@ -184,8 +184,8 @@ struct sequence { // would be called from sequence::invoke only. template - static result>, none_t> - invoke(location& loc, region> reg, Iterator first) + static result + invoke(location& loc, region reg, Iterator first) { const auto rslt = Head::invoke(loc); if(rslt.is_err()) @@ -204,7 +204,7 @@ struct either; template struct either { - static result>, none_t> + static result invoke(location& loc) { const auto rslt = Head::invoke(loc); @@ -215,7 +215,7 @@ struct either template struct either { - static result>, none_t> + static result invoke(location& loc) { return Head::invoke(loc); @@ -232,10 +232,10 @@ struct unlimited{}; template struct repeat> { - static result>, none_t> + 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> { - static result>, none_t> + 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 { - static result>, none_t> + static result invoke(location& loc) { - region> retval(loc); + region retval(loc); while(true) { auto rslt = T::invoke(loc); diff --git a/toml/parser.hpp b/toml/parser.hpp index 6ab5252..084bbd7 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -25,7 +25,7 @@ namespace toml namespace detail { -inline result>>, std::string> +inline result, std::string> parse_boolean(location& loc) { const auto first = loc.iter(); @@ -47,7 +47,7 @@ parse_boolean(location& loc) {{std::addressof(loc), "the next token is not a boolean"}})); } -inline result>>, std::string> +inline result, std::string> parse_binary_integer(location& loc) { const auto first = loc.iter(); @@ -76,7 +76,7 @@ parse_binary_integer(location& loc) {{std::addressof(loc), "the next token is not an integer"}})); } -inline result>>, std::string> +inline result, std::string> parse_octal_integer(location& loc) { const auto first = loc.iter(); @@ -96,7 +96,7 @@ parse_octal_integer(location& loc) {{std::addressof(loc), "the next token is not an integer"}})); } -inline result>>, std::string> +inline result, std::string> parse_hexadecimal_integer(location& loc) { const auto first = loc.iter(); @@ -116,7 +116,7 @@ parse_hexadecimal_integer(location& loc) {{std::addressof(loc), "the next token is not an integer"}})); } -inline result>>, std::string> +inline result, std::string> parse_integer(location& loc) { const auto first = loc.iter(); @@ -125,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 @@ -161,7 +161,7 @@ parse_integer(location& loc) {{std::addressof(loc), "the next token is not an integer"}})); } -inline result>>, std::string> +inline result, std::string> parse_floating(location& loc) { const auto first = loc.iter(); @@ -249,9 +249,7 @@ parse_floating(location& loc) {{std::addressof(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; @@ -363,7 +361,7 @@ inline result parse_escape_sequence(location& loc) return err(msg); } -inline result>>, std::string> +inline result, std::string> parse_ml_basic_string(location& loc) { const auto first = loc.iter(); @@ -442,7 +440,7 @@ parse_ml_basic_string(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_basic_string(location& loc) { const auto first = loc.iter(); @@ -494,7 +492,7 @@ parse_basic_string(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_ml_literal_string(location& loc) { const auto first = loc.iter(); @@ -556,7 +554,7 @@ parse_ml_literal_string(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_literal_string(location& loc) { const auto first = loc.iter(); @@ -596,7 +594,7 @@ parse_literal_string(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_string(location& loc) { if(loc.iter() != loc.end() && *(loc.iter()) == '"') @@ -627,7 +625,7 @@ parse_string(location& loc) {{std::addressof(loc), "the next token is not a string"}})); } -inline result>>, std::string> +inline result, std::string> parse_local_date(location& loc) { const auto first = loc.iter(); @@ -676,7 +674,7 @@ parse_local_date(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_local_time(location& loc) { const auto first = loc.iter(); @@ -764,7 +762,7 @@ parse_local_time(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_local_datetime(location& loc) { const auto first = loc.iter(); @@ -808,7 +806,7 @@ parse_local_datetime(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_offset_datetime(location& loc) { const auto first = loc.iter(); @@ -856,7 +854,7 @@ parse_offset_datetime(location& loc) } } -inline result>>, std::string> +inline result, std::string> parse_simple_key(location& loc) { if(const auto bstr = parse_basic_string(loc)) @@ -877,7 +875,7 @@ parse_simple_key(location& loc) } // dotted key become vector of keys -inline result, region>>, std::string> +inline result, region>, std::string> parse_key(location& loc) { const auto first = loc.iter(); @@ -939,7 +937,7 @@ template result parse_value(location&); template -result>>, std::string> +result, std::string> parse_array(location& loc) { using value_type = Value; @@ -968,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)) @@ -1021,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 { @@ -1044,7 +1042,7 @@ parse_array(location& loc) } template -result, region>>, Value>, std::string> +result, region>, Value>, std::string> parse_key_value_pair(location& loc) { using value_type = Value; @@ -1133,7 +1131,7 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last) } // forward decl for is_valid_forward_table_definition -result, region>>, std::string> +result, region>, std::string> parse_table_key(location& loc); // The following toml file is allowed. @@ -1205,7 +1203,7 @@ 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_same -result>>, std::string> +result, std::string> parse_inline_table(location& loc) { using value_type = Value; @@ -1461,7 +1459,7 @@ parse_inline_table(location& loc) { loc.advance(); // skip `}` return ok(std::make_pair(retval, - region>(loc, first, loc.iter()))); + region(loc, first, loc.iter()))); } const auto kv_r = parse_key_value_pair(loc); @@ -1492,7 +1490,7 @@ 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') { @@ -1709,7 +1707,7 @@ result parse_value(location& loc) } } -inline result, region>>, std::string> +inline result, region>, std::string> parse_table_key(location& loc) { if(auto token = lex_std_table::invoke(loc)) @@ -1770,7 +1768,7 @@ parse_table_key(location& loc) } } -inline result, region>>, std::string> +inline result, region>, std::string> parse_array_table_key(location& loc) { if(auto token = lex_array_table::invoke(loc)) @@ -1927,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. diff --git a/toml/region.hpp b/toml/region.hpp index 55a748d..fde6d50 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -194,16 +194,10 @@ 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; diff --git a/toml/value.hpp b/toml/value.hpp index d2f8cb9..d0af508 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -1056,95 +1056,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)) {} From 7fb93e2f544f9852be75cb3d8e95a6913fb845f0 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 00:20:26 +0900 Subject: [PATCH 07/16] fix: add missing `explicit` to detail::region --- toml/region.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index fde6d50..35cf998 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -202,11 +202,11 @@ struct region final : public region_base // 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()) {} From e696aabd11beb80a2569eafe0d8c5eb48ae29c6b Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 00:48:04 +0900 Subject: [PATCH 08/16] refactor: change internal interface to reduce code to remove `std::addressof` calls, get_region(toml::value) now returns a pointer to region. --- toml/get.hpp | 20 ++++++++-------- toml/parser.hpp | 63 +++++++++++++++++++++---------------------------- toml/value.hpp | 31 +++++++++++------------- 3 files changed, 51 insertions(+), 63 deletions(-) diff --git a/toml/get.hpp b/toml/get.hpp index 93b834a..d2353a6 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -189,7 +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)), + {detail::get_region(v), concat_to_string("the actual type is ", v.type())} }), v.location()); } @@ -336,7 +336,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"} + {detail::get_region(v), "here"} })); } std::transform(ar.cbegin(), ar.cend(), container.begin(), @@ -361,7 +361,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"} + {detail::get_region(v), "here"} })); } return std::make_pair(::toml::get(ar.at(0)), @@ -393,7 +393,7 @@ get(const basic_value& v) "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"} + {detail::get_region(v), "here"} })); } return detail::get_tuple_impl(ar, @@ -512,7 +512,7 @@ find(const basic_value& v, const std::size_t 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"} + {detail::get_region(v), "in this array"} })); } return ary.at(idx); @@ -526,7 +526,7 @@ basic_value& find(basic_value& v, const std::size_t 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"} + {detail::get_region(v), "in this array"} })); } return ary.at(idx); @@ -540,7 +540,7 @@ basic_value find(basic_value&& v, const std::size_t 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"} + {detail::get_region(v), "in this array"} })); } return basic_value(std::move(ary.at(idx))); @@ -600,7 +600,7 @@ find(const basic_value& v, const std::size_t 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"} + {detail::get_region(v), "in this array"} })); } return ::toml::get(ary.at(idx)); @@ -615,7 +615,7 @@ find(basic_value& v, const std::size_t 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"} + {detail::get_region(v), "in this array"} })); } return ::toml::get(ary.at(idx)); @@ -630,7 +630,7 @@ find(basic_value&& v, const std::size_t 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"} + {detail::get_region(v), "in this array"} })); } return ::toml::get(std::move(ary.at(idx))); diff --git a/toml/parser.hpp b/toml/parser.hpp index 084bbd7..4e6d75f 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -986,11 +986,11 @@ parse_array(location& loc) "type of elements should be the same each other.", { {std::addressof(array_start_loc), "array starts here"}, { - std::addressof(get_region(retval.front())), + get_region(retval.front()), "value has type " + stringize(retval.front().type()) }, { - std::addressof(get_region(val.unwrap())), + get_region(val.unwrap()), "value has different type, " + stringize(val.unwrap().type()) } }), source_location(std::addressof(loc))); @@ -1161,7 +1161,7 @@ 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()); + location def("internal", detail::get_region(fwd)->str()); if(const auto tabkeys = parse_table_key(def)) { // table keys always contains all the nodes from the root. @@ -1236,10 +1236,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") cannot be defined"), { - {std::addressof(get_region(tab->at(k))), - "table already defined"}, - {std::addressof(get_region(v)), - "this conflicts with the previous table"} + {get_region(tab->at(k)), "table already defined"}, + {get_region(v), "this conflicts with the previous table"} }), v.location()); } else if(!(tab->at(k).is_array())) @@ -1248,10 +1246,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))), + {get_region(tab->at(k)), concat_to_string("this ", tab->at(k).type(), " value already exists")}, - {std::addressof(get_region(v)), + {get_region(v), "while inserting this array-of-tables"} }), v.location()); } @@ -1263,10 +1261,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))), + {get_region(tab->at(k)), concat_to_string("this ", tab->at(k).type(), " value already exists")}, - {std::addressof(get_region(v)), + {get_region(v), "while inserting this array-of-tables"} }), v.location()); } @@ -1285,16 +1283,16 @@ 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(detail::get_region(a.front())->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"), { - {std::addressof(get_region(tab->at(k))), + {get_region(tab->at(k)), concat_to_string("this ", tab->at(k).type(), " value has static size")}, - {std::addressof(get_region(v)), + {get_region(v), "appending it to the statically sized array"} }), v.location()); } @@ -1320,10 +1318,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"} + {get_region(tab->at(k)), "table already exists here"}, + {get_region(v), "table defined twice"} }), v.location()); } // to allow the following toml file. @@ -1347,10 +1343,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"} + {get_region(tab->at(k)), "array of tables defined here"}, + {get_region(v), "table conflicts with the previous array of table"} }), v.location()); } else @@ -1358,10 +1352,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"} + {get_region(tab->at(k)), "value already exists here"}, + {get_region(v), "value defined twice"} }), v.location()); } } @@ -1390,15 +1382,14 @@ insert_nested_key(typename Value::table_type& root, const Value& v, { // 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(get_region(tab->at(k))->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"} + {get_region(tab->at(k)), "inline tables are immutable"}, + {get_region(v), "inserting this"} }), v.location()); } } @@ -1413,9 +1404,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"} + {get_region(a.back()), concat_to_string( + "actual type is ", a.back().type())}, + {get_region(v), "inserting this"} }), v.location()); } tab = std::addressof(a.back().as_table()); @@ -1426,9 +1417,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"} + {get_region(tab->at(k)), concat_to_string( + "actual type is ", tab->at(k).type())}, + {get_region(v), "inserting this"} }), v.location()); } } diff --git a/toml/value.hpp b/toml/value.hpp index d0af508..b74aac5 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -22,9 +22,9 @@ 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 @@ -46,8 +46,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)} + {get_region(v), concat_to_string("the actual type is ", actual)} }), v.location()); } @@ -74,8 +73,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* reg = get_region(v); + if(reg->line_num() == "1" && reg->size() == 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 +110,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"} + {reg, "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"), { {reg, "in this table"} })); } } @@ -1710,7 +1707,7 @@ 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); @@ -1920,7 +1917,7 @@ inline std::string format_error(const std::string& err_msg, { return detail::format_underline(err_msg, std::vector>{ - {std::addressof(detail::get_region(v)), comment} + {detail::get_region(v), comment} }, std::move(hints), colorize); } @@ -1933,8 +1930,8 @@ inline std::string format_error(const std::string& err_msg, { return detail::format_underline(err_msg, std::vector>{ - {std::addressof(detail::get_region(v1)), comment1}, - {std::addressof(detail::get_region(v2)), comment2} + {detail::get_region(v1), comment1}, + {detail::get_region(v2), comment2} }, std::move(hints), colorize); } @@ -1948,9 +1945,9 @@ inline std::string format_error(const std::string& err_msg, { 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} + {detail::get_region(v1), comment1}, + {detail::get_region(v2), comment2}, + {detail::get_region(v3), comment3} }, std::move(hints), colorize); } From ce68f6f4c2045db7fb72f0e235a59544cd6f74cb Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 21:32:35 +0900 Subject: [PATCH 09/16] refactor: check (always-valid) ptr before deref --- toml/parser.hpp | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index 4e6d75f..5710309 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -1161,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. @@ -1283,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"), { - {get_region(tab->at(k)), - concat_to_string("this ", tab->at(k).type(), - " value has static size")}, - {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"), { + {get_region(tab->at(k)), + concat_to_string("this ", tab->at(k).type(), + " value has static size")}, + {get_region(v), + "appending it to the statically sized array"} + }), v.location()); + } } a.push_back(v); return ok(true); @@ -1379,10 +1387,11 @@ 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 (", From 32a5341d09dc1106bb316fa8a1a869b5a1aa4139 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 22:29:18 +0900 Subject: [PATCH 10/16] refactor: use source_location, not region_base* --- toml/get.hpp | 20 +-- toml/parser.hpp | 298 +++++++++++++++++++-------------------- toml/region.hpp | 101 ------------- toml/source_location.hpp | 122 ++++++++++++++++ toml/value.hpp | 36 ++--- 5 files changed, 296 insertions(+), 281 deletions(-) diff --git a/toml/get.hpp b/toml/get.hpp index d2353a6..cd0b034 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -189,7 +189,7 @@ get(const basic_value& v) { throw type_error(detail::format_underline("toml::value: " "bad_cast to std::chrono::system_clock::time_point", { - {detail::get_region(v), + {source_location(detail::get_region(v)), concat_to_string("the actual type is ", v.type())} }), v.location()); } @@ -336,7 +336,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."), { - {detail::get_region(v), "here"} + {source_location(detail::get_region(v)), "here"} })); } std::transform(ar.cbegin(), ar.cend(), container.begin(), @@ -361,7 +361,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."), { - {detail::get_region(v), "here"} + {source_location(detail::get_region(v)), "here"} })); } return std::make_pair(::toml::get(ar.at(0)), @@ -393,7 +393,7 @@ get(const basic_value& v) "toml::get: specified std::tuple with ", std::tuple_size::value, " elements, but there are ", ar.size(), " elements in toml array."), { - {detail::get_region(v), "here"} + {source_location(detail::get_region(v)), "here"} })); } return detail::get_tuple_impl(ar, @@ -512,7 +512,7 @@ find(const basic_value& v, const std::size_t idx) { throw std::out_of_range(detail::format_underline(concat_to_string( "index ", idx, " is out of range"), { - {detail::get_region(v), "in this array"} + {source_location(detail::get_region(v)), "in this array"} })); } return ary.at(idx); @@ -526,7 +526,7 @@ basic_value& find(basic_value& v, const std::size_t idx) { throw std::out_of_range(detail::format_underline(concat_to_string( "index ", idx, " is out of range"), { - {detail::get_region(v), "in this array"} + {source_location(detail::get_region(v)), "in this array"} })); } return ary.at(idx); @@ -540,7 +540,7 @@ basic_value find(basic_value&& v, const std::size_t idx) { throw std::out_of_range(detail::format_underline(concat_to_string( "index ", idx, " is out of range"), { - {detail::get_region(v), "in this array"} + {source_location(detail::get_region(v)), "in this array"} })); } return basic_value(std::move(ary.at(idx))); @@ -600,7 +600,7 @@ find(const basic_value& v, const std::size_t idx) { throw std::out_of_range(detail::format_underline(concat_to_string( "index ", idx, " is out of range"), { - {detail::get_region(v), "in this array"} + {source_location(detail::get_region(v)), "in this array"} })); } return ::toml::get(ary.at(idx)); @@ -615,7 +615,7 @@ find(basic_value& v, const std::size_t idx) { throw std::out_of_range(detail::format_underline(concat_to_string( "index ", idx, " is out of range"), { - {detail::get_region(v), "in this array"} + {source_location(detail::get_region(v)), "in this array"} })); } return ::toml::get(ary.at(idx)); @@ -630,7 +630,7 @@ find(basic_value&& v, const std::size_t idx) { throw std::out_of_range(detail::format_underline(concat_to_string( "index ", idx, " is out of range"), { - {detail::get_region(v), "in this array"} + {source_location(detail::get_region(v)), "in this array"} })); } return ::toml::get(std::move(ary.at(idx))); diff --git a/toml/parser.hpp b/toml/parser.hpp index 5710309..6d3b73c 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -38,13 +38,13 @@ parse_boolean(location& loc) { throw internal_error(format_underline( "toml::parse_boolean: internal error", - {{std::addressof(reg), "invalid token"}}), + {{source_location(reg), "invalid token"}}), source_location(std::addressof(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"}})); } inline result, std::string> @@ -65,7 +65,7 @@ parse_binary_integer(location& loc) { throw internal_error(format_underline( "toml::parse_integer: internal error", - {{std::addressof(token.unwrap()), "invalid token"}}), + {{source_location(token.unwrap()), "invalid token"}}), source_location(std::addressof(loc))); } } @@ -73,7 +73,7 @@ parse_binary_integer(location& loc) } 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"}})); } inline result, std::string> @@ -93,7 +93,7 @@ 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"}})); } inline result, std::string> @@ -113,7 +113,7 @@ 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"}})); } inline result, std::string> @@ -136,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"}})); } } @@ -158,7 +158,7 @@ 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"}})); } inline result, std::string> @@ -246,7 +246,7 @@ 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"}})); } inline std::string read_utf8_codepoint(const region& reg, const location& loc) @@ -279,7 +279,7 @@ inline std::string read_utf8_codepoint(const region& reg, const location& loc) 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(loc), "not a valid UTF-8 codepoint" }}), source_location(std::addressof(loc))); } assert(codepoint < 0xD800 || 0xDFFF < codepoint); @@ -300,7 +300,7 @@ inline std::string read_utf8_codepoint(const region& reg, const location& loc) { throw syntax_error(format_underline("toml::read_utf8_codepoint:" " input codepoint is too large.", - {{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}), + {{source_location(loc), "should be in [0x00..0x10FFFF]"}}), source_location(std::addressof(loc))); } return character; @@ -312,7 +312,7 @@ inline result parse_escape_sequence(location& loc) 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()) @@ -334,7 +334,7 @@ inline 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': @@ -347,13 +347,13 @@ inline 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*>'"}); @@ -378,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); @@ -405,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); } @@ -425,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())); @@ -436,7 +436,7 @@ 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"}})); } } @@ -453,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; @@ -476,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); } @@ -488,7 +488,7 @@ 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"}})); } } @@ -505,8 +505,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)); } // immediate newline is ignored (if exists) /* discard return value */ lex_newline::invoke(inner_loc); @@ -518,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 @@ -538,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), @@ -550,7 +550,7 @@ 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"}})); } } @@ -567,8 +567,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)); } const auto body = repeat::invoke(inner_loc); @@ -578,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), @@ -590,7 +590,7 @@ 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"}})); } } @@ -622,7 +622,7 @@ 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"}})); } inline result, std::string> @@ -638,8 +638,8 @@ parse_local_date(location& loc) { 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); @@ -647,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); @@ -656,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)), @@ -670,7 +670,7 @@ 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"}})); } } @@ -687,8 +687,8 @@ parse_local_time(location& loc) { 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); @@ -696,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); @@ -705,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), @@ -748,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())); @@ -758,7 +758,7 @@ 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"}})); } } @@ -774,16 +774,16 @@ parse_local_datetime(location& loc) { 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); @@ -791,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), @@ -802,7 +802,7 @@ 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"}})); } } @@ -818,8 +818,8 @@ parse_offset_datetime(location& loc) { 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)) @@ -840,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())); @@ -850,7 +850,7 @@ 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"}})); } } @@ -871,7 +871,7 @@ 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 @@ -897,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); @@ -914,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)); @@ -929,7 +929,7 @@ 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 @@ -984,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"}, { - get_region(retval.front()), + retval.front().location(), "value has type " + stringize(retval.front().type()) }, { - 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())); @@ -1005,8 +1005,8 @@ 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(array_start_loc), "array starts here"}, + {source_location(loc), "it is not a valid value."} }), source_location(std::addressof(loc))); } @@ -1028,8 +1028,8 @@ 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(array_start_loc), "array starts here"}, + {source_location(loc), "should be `,`"} }), source_location(std::addressof(loc))); } } @@ -1037,7 +1037,7 @@ parse_array(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(loc), "should be closed"}}), source_location(std::addressof(loc))); } @@ -1059,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)); } @@ -1075,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_-]."}); } @@ -1083,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)); @@ -1101,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. { @@ -1241,8 +1241,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") cannot be defined"), { - {get_region(tab->at(k)), "table already defined"}, - {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())) @@ -1251,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"), { - {get_region(tab->at(k)), + {tab->at(k).location(), concat_to_string("this ", tab->at(k).type(), " value already exists")}, - {get_region(v), + {v.location(), "while inserting this array-of-tables"} }), v.location()); } @@ -1266,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"), { - {get_region(tab->at(k)), + {tab->at(k).location(), concat_to_string("this ", tab->at(k).type(), " value already exists")}, - {get_region(v), + {v.location(), "while inserting this array-of-tables"} }), v.location()); } @@ -1296,10 +1296,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 array-of-tables"), { - {get_region(tab->at(k)), + {tab->at(k).location(), concat_to_string("this ", tab->at(k).type(), " value has static size")}, - {get_region(v), + {v.location(), "appending it to the statically sized array"} }), v.location()); } @@ -1326,8 +1326,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: table (\"", format_dotted_keys(first, last), "\") already exists."), { - {get_region(tab->at(k)), "table already exists here"}, - {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. @@ -1351,8 +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."), { - {get_region(tab->at(k)), "array of tables defined here"}, - {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 @@ -1360,8 +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."), { - {get_region(tab->at(k)), "value already exists here"}, - {get_region(v), "value defined twice"} + {tab->at(k).location(), "value already exists here"}, + {v.location(), "value defined twice"} }), v.location()); } } @@ -1397,8 +1397,8 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "toml::insert_value: inserting to an inline table (", format_dotted_keys(first, std::next(iter)), ") but inline tables are immutable"), { - {get_region(tab->at(k)), "inline tables are immutable"}, - {get_region(v), "inserting this"} + {tab->at(k).location(), "inline tables are immutable"}, + {v.location(), "inserting this"} }), v.location()); } } @@ -1413,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"), { - {get_region(a.back()), concat_to_string( + {a.back().location(), concat_to_string( "actual type is ", a.back().type())}, - {get_region(v), "inserting this"} + {v.location(), "inserting this"} }), v.location()); } tab = std::addressof(a.back().as_table()); @@ -1426,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"), { - {get_region(tab->at(k)), concat_to_string( + {tab->at(k).location(), concat_to_string( "actual type is ", tab->at(k).type())}, - {get_region(v), "inserting this"} + {v.location(), "inserting this"} }), v.location()); } } @@ -1448,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 @@ -1496,23 +1496,23 @@ parse_inline_table(location& loc) { 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)); } inline result guess_number_type(const location& l) @@ -1535,7 +1535,7 @@ inline 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); @@ -1555,14 +1555,14 @@ inline 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"})); } @@ -1571,7 +1571,7 @@ inline 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"})); } @@ -1588,7 +1588,7 @@ inline 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"})); } @@ -1604,7 +1604,7 @@ inline 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"})); } @@ -1613,21 +1613,21 @@ inline 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"})); } @@ -1637,19 +1637,19 @@ inline 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"}})); } inline result guess_value_type(const location& loc) @@ -1677,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); @@ -1700,7 +1700,7 @@ 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); } @@ -1719,8 +1719,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)); } // to skip [ a . b . c ] // ^----------- this whitespace @@ -1730,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 @@ -1741,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. @@ -1755,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())); @@ -1764,7 +1764,7 @@ 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"}})); } } @@ -1780,8 +1780,8 @@ parse_array_table_key(location& loc) { 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); @@ -1789,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); @@ -1798,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. @@ -1812,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())); @@ -1821,7 +1821,7 @@ 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"}})); } } @@ -1896,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); @@ -2010,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); diff --git a/toml/region.hpp b/toml/region.hpp index 35cf998..6761aed 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -412,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/source_location.hpp b/toml/source_location.hpp index 8c14b96..8e6f267 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,112 @@ 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) +{ + assert(!loc_com.empty()); + + const auto line_num_width = static_cast(std::to_string(std::max_element( + loc_com.begin(), loc_com.end(), + [](std::pair const& lhs, + std::pair const& rhs) + { + return std::to_string(lhs.first.line()).size() < + std::to_string(rhs.first.line()).size(); + } + )->first.line()).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 = loc_com.begin(); iter != loc_com.end(); ++iter) + { + // if the filenames are the same, print "..." + if(iter != loc_com.begin() && + std::prev(iter)->first.file_name() == iter->first.file_name()) + { + retval << color::bold << color::blue << "\n ...\n" << color::reset; + } + else // if filename differs, print " --> filename.toml" + { + if(iter != loc_com.begin()) {retval << '\n';} + + retval << color::bold << color::blue << " --> " << color::reset + << iter->first.file_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 source_location& loc = iter->first; + const std::string& comment = iter->second; + + retval << ' ' << color::bold << color::blue << std::setw(line_num_width) + << std::right << loc.line() << " | " << color::reset + << loc.line_str() << '\n'; + + retval << make_string(static_cast(line_num_width + 1), ' ') + << color::bold << color::blue << " | " << color::reset + << make_string(loc.column()-1 /*1-origin*/, ' '); + + if(loc.region() == 1) + { + // invalid + // ^------ + retval << color::bold << color::red << "^---" << color::reset; + } + else + { + // invalid + // ~~~~~~~ + const auto underline_len = (std::min)( + static_cast(loc.region()), loc.line_str().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_SOURCE_LOCATION_HPP diff --git a/toml/value.hpp b/toml/value.hpp index b74aac5..95270d1 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -46,7 +46,8 @@ 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), { - {get_region(v), concat_to_string("the actual type is ", actual)} + {source_location(get_region(v)), + concat_to_string("the actual type is ", actual)} }), v.location()); } @@ -73,8 +74,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 = source_location(get_region(v)); + 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 @@ -110,14 +111,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"), { - {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"), { {reg, "in this table"} })); + "key \"", ky, "\" not found"), { {loc, "in this table"} })); } } @@ -1567,7 +1568,7 @@ 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(), + {source_location(this->region_info_.get()), concat_to_string("the length is ", this->as_array(std::nothrow).size(), ", and the specified index is ", idx)} })); @@ -1585,7 +1586,7 @@ 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(), + {source_location(this->region_info_.get()), concat_to_string("the length is ", this->as_array(std::nothrow).size(), ", and the specified index is ", idx)} })); @@ -1657,7 +1658,7 @@ class basic_value { throw type_error(detail::format_underline( "toml::value::size(): bad_cast to container types", { - {this->region_info_.get(), + {source_location(this->region_info_.get()), concat_to_string("the actual type is ", this->type_)} }), this->location()); } @@ -1915,10 +1916,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>{ - {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> @@ -1928,10 +1927,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>{ - {detail::get_region(v1), comment1}, - {detail::get_region(v2), comment2} + return detail::format_underline(err_msg, { + {v1.location(), comment1}, {v2.location(), comment2} }, std::move(hints), colorize); } @@ -1943,11 +1940,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>{ - {detail::get_region(v1), comment1}, - {detail::get_region(v2), comment2}, - {detail::get_region(v3), comment3} + return detail::format_underline(err_msg, {{v1.location(), comment1}, + {v2.location(), comment2}, {v3.location(), comment3} }, std::move(hints), colorize); } From 68e8a3165950c43fb0d3485015a41a761a5055bd Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 23:00:40 +0900 Subject: [PATCH 11/16] refactor: remove needless addressof() call --- toml/literal.hpp | 3 +-- toml/parser.hpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/toml/literal.hpp b/toml/literal.hpp index 65a5511..5292b3d 100644 --- a/toml/literal.hpp +++ b/toml/literal.hpp @@ -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 6d3b73c..7ef196a 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -39,7 +39,7 @@ parse_boolean(location& loc) throw internal_error(format_underline( "toml::parse_boolean: internal error", {{source_location(reg), "invalid token"}}), - source_location(std::addressof(reg))); + source_location(reg)); } } loc.reset(first); //rollback @@ -66,7 +66,7 @@ parse_binary_integer(location& loc) throw internal_error(format_underline( "toml::parse_integer: internal error", {{source_location(token.unwrap()), "invalid token"}}), - source_location(std::addressof(loc))); + source_location(loc)); } } return ok(std::make_pair(retval, token.unwrap())); @@ -280,7 +280,7 @@ inline std::string read_utf8_codepoint(const region& reg, const location& loc) "toml::read_utf8_codepoint: codepoints in the range " "[0xD800, 0xDFFF] are not valid UTF-8.", {{ source_location(loc), "not a valid UTF-8 codepoint" - }}), source_location(std::addressof(loc))); + }}), source_location(loc)); } assert(codepoint < 0xD800 || 0xDFFF < codepoint); // 1110yyyy 10yxxxxx 10xxxxxx @@ -301,7 +301,7 @@ inline std::string read_utf8_codepoint(const region& reg, const location& loc) throw syntax_error(format_underline("toml::read_utf8_codepoint:" " input codepoint is too large.", {{source_location(loc), "should be in [0x00..0x10FFFF]"}}), - source_location(std::addressof(loc))); + source_location(loc)); } return character; } @@ -1007,7 +1007,7 @@ parse_array(location& loc) "value having invalid format appeared in an array", { {source_location(array_start_loc), "array starts here"}, {source_location(loc), "it is not a valid value."} - }), source_location(std::addressof(loc))); + }), source_location(loc)); } using lex_array_separator = sequence, character<','>>; @@ -1030,7 +1030,7 @@ parse_array(location& loc) " missing array separator `,` after a value", { {source_location(array_start_loc), "array starts here"}, {source_location(loc), "should be `,`"} - }), source_location(std::addressof(loc))); + }), source_location(loc)); } } } @@ -1038,7 +1038,7 @@ parse_array(location& loc) throw syntax_error(format_underline("toml::parse_array: " "array did not closed by `]`", {{source_location(loc), "should be closed"}}), - source_location(std::addressof(loc))); + source_location(loc)); } template @@ -1478,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<','>>; @@ -2067,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(); } From bc219af5b5ee6ad3cd48dbb98e4eaabb5afcb3af Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 23:03:33 +0900 Subject: [PATCH 12/16] refactor: use location() member instead of ctor --- toml/value.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/toml/value.hpp b/toml/value.hpp index 95270d1..013920f 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -46,8 +46,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), { - {source_location(get_region(v)), - concat_to_string("the actual type is ", actual)} + {v.location(), concat_to_string("the actual type is ", actual)} }), v.location()); } @@ -74,7 +73,7 @@ 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 loc = source_location(get_region(v)); + const auto loc = v.location(); if(loc.line() == 1 && loc.region() == 1) { // Here it assumes that top-level table starts at the first character. @@ -1568,9 +1567,9 @@ class basic_value { throw std::out_of_range(detail::format_underline( "toml::value::at(idx): no element corresponding to the index", { - {source_location(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); @@ -1586,9 +1585,9 @@ class basic_value { throw std::out_of_range(detail::format_underline( "toml::value::at(idx): no element corresponding to the index", { - {source_location(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); @@ -1658,7 +1657,7 @@ class basic_value { throw type_error(detail::format_underline( "toml::value::size(): bad_cast to container types", { - {source_location(this->region_info_.get()), + {this->location(), concat_to_string("the actual type is ", this->type_)} }), this->location()); } From 22ace027ded0e120b1d79196cdb020ed1c6d584a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 23:04:24 +0900 Subject: [PATCH 13/16] refactor: rm template from detail::change_region --- toml/value.hpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/toml/value.hpp b/toml/value.hpp index 013920f..9fa7b9c 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -27,16 +27,10 @@ inline region_base const* get_region(const Value& v) 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; } @@ -1709,8 +1703,8 @@ class basic_value template 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, region reg); private: From 4b719f080684bee386bbf89a71ddc0553307cc1b Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 27 Jul 2020 23:15:14 +0900 Subject: [PATCH 14/16] refactor: use location() instead of get_region --- toml/get.hpp | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/toml/get.hpp b/toml/get.hpp index cd0b034..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", { - {source_location(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."), { - {source_location(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."), { - {source_location(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."), { - {source_location(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"), { - {source_location(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"), { - {source_location(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"), { - {source_location(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"), { - {source_location(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"), { - {source_location(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"), { - {source_location(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))); } From f23c003d2fe2d05ce32ddc79881a7a38ed90a440 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 28 Jul 2020 00:04:25 +0900 Subject: [PATCH 15/16] fix: add missing namespace specifier --- toml/value.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml/value.hpp b/toml/value.hpp index 9fa7b9c..76eee0d 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -1704,7 +1704,7 @@ class basic_value friend region_base const* detail::get_region(const Value& v); template - friend void detail::change_region(Value& v, region reg); + friend void detail::change_region(Value& v, detail::region reg); private: From 4e6ae9a994598e34bd9293f90e5d76c7da5d3f74 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jul 2020 16:11:35 +0900 Subject: [PATCH 16/16] refactor: avoid string construct in format_ul --- toml/source_location.hpp | 119 +++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 48 deletions(-) diff --git a/toml/source_location.hpp b/toml/source_location.hpp index 8e6f267..26ff216 100644 --- a/toml/source_location.hpp +++ b/toml/source_location.hpp @@ -107,17 +107,20 @@ inline std::string format_underline(const std::string& message, const std::vector& helps = {}, const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { - assert(!loc_com.empty()); - - const auto line_num_width = static_cast(std::to_string(std::max_element( - loc_com.begin(), loc_com.end(), - [](std::pair const& lhs, - std::pair const& rhs) + 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) { - return std::to_string(lhs.first.line()).size() < - std::to_string(rhs.first.line()).size(); + line /= 10; + digit += 1; } - )->first.line()).size()); + 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; @@ -142,58 +145,78 @@ inline std::string format_underline(const std::string& message, << color::bold << message << color::reset << '\n'; } - for(auto iter = loc_com.begin(); iter != loc_com.end(); ++iter) + 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; ifirst.file_name() == iter->first.file_name()) + if(prev.first.file_name() == curr.first.file_name()) { - retval << color::bold << color::blue << "\n ...\n" << color::reset; + retval << color::bold << color::blue << " ...\n" << color::reset; } - else // if filename differs, print " --> filename.toml" + else // if filename differs, print " --> filename.toml" again { - if(iter != loc_com.begin()) {retval << '\n';} - retval << color::bold << color::blue << " --> " << color::reset - << iter->first.file_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'; + << curr.first.file_name() << '\n'; + retval << make_string(line_num_width + 1, ' ') + << color::bold << color::blue << " |\n" << color::reset; } - const source_location& loc = iter->first; - const std::string& comment = iter->second; - retval << ' ' << color::bold << color::blue << std::setw(line_num_width) - << std::right << loc.line() << " | " << color::reset - << loc.line_str() << '\n'; - - retval << make_string(static_cast(line_num_width + 1), ' ') - << color::bold << color::blue << " | " << color::reset - << make_string(loc.column()-1 /*1-origin*/, ' '); - - if(loc.region() == 1) - { - // invalid - // ^------ - retval << color::bold << color::red << "^---" << color::reset; - } - else - { - // invalid - // ~~~~~~~ - const auto underline_len = (std::min)( - static_cast(loc.region()), loc.line_str().size()); - retval << color::bold << color::red - << make_string(underline_len, '~') << color::reset; - } - retval << ' '; - retval << comment; + format_one_location(retval, curr.first, curr.second); } if(!helps.empty()) { retval << '\n'; - retval << make_string(static_cast(line_num_width + 1), ' '); + retval << make_string(line_num_width + 1, ' '); retval << color::bold << color::blue << " | " << color::reset; for(const auto& help : helps) {