chore: merge branch 'master' into is-something

This commit is contained in:
ToruNiina
2019-03-15 17:25:17 +09:00
10 changed files with 453 additions and 345 deletions

View File

@@ -12,8 +12,39 @@ matrix:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
- g++-5 - g++-5
- build-essential - libboost-all-dev
- cmake - os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-6"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
- libboost-all-dev
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-7"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
- libboost-all-dev
- os: linux
language: cpp
compiler: gcc
env: COMPILER="g++-8"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
- libboost-all-dev - libboost-all-dev
- os: linux - os: linux
language: cpp language: cpp
@@ -26,8 +57,66 @@ matrix:
- llvm-toolchain-precise-3.7 - llvm-toolchain-precise-3.7
packages: packages:
- clang-3.7 - clang-3.7
- build-essential - libboost-all-dev
- cmake - os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-4.0"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
packages:
- clang-4.0
- libboost-all-dev
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-5.0"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
packages:
- clang-5.0
- libboost-all-dev
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-6.0"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
packages:
- clang-6.0
- libboost-all-dev
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-7"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
packages:
- clang-7
- libboost-all-dev
- os: linux
language: cpp
compiler: clang
env: COMPILER="clang++-8"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
packages:
- clang-8
- libboost-all-dev - libboost-all-dev
- os: osx - os: osx
language: cpp language: cpp

View File

@@ -28,6 +28,7 @@ set(TEST_NAMES
test_serialize_file test_serialize_file
test_parse_unicode test_parse_unicode
test_error_detection test_error_detection
test_format_error
) )
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL) CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)

View File

@@ -0,0 +1,75 @@
#define BOOST_TEST_MODULE "test_value"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
// to check it successfully compiles. it does not check the formatted string.
BOOST_AUTO_TEST_CASE(test_1_value)
{
toml::value val(42);
{
const std::string pretty_error =
toml::format_error("[error] test error", val, "this is a value");
std::cout << pretty_error << std::endl;
}
{
const std::string pretty_error =
toml::format_error("[error] test error", val, "this is a value",
std::vector<std::string>{"this is a hint"});
std::cout << pretty_error << std::endl;
}
}
BOOST_AUTO_TEST_CASE(test_2_values)
{
toml::value v1(42);
toml::value v2(3.14);
{
const std::string pretty_error =
toml::format_error("[error] test error with two values",
v1, "this is the answer",
v2, "this is the pi");
std::cout << pretty_error << std::endl;
}
{
const std::string pretty_error =
toml::format_error("[error] test error with two values",
v1, "this is the answer",
v2, "this is the pi",
std::vector<std::string>{"hint"});
std::cout << pretty_error << std::endl;
}
}
BOOST_AUTO_TEST_CASE(test_3_values)
{
toml::value v1(42);
toml::value v2(3.14);
toml::value v3("foo");
{
const std::string pretty_error =
toml::format_error("[error] test error with two values",
v1, "this is the answer",
v2, "this is the pi",
v3, "this is a meta-syntactic variable");
std::cout << pretty_error << std::endl;
}
{
const std::string pretty_error =
toml::format_error("[error] test error with two values",
v1, "this is the answer",
v2, "this is the pi",
v3, "this is a meta-syntactic variable",
std::vector<std::string>{"hint 1", "hint 2"});
std::cout << pretty_error << std::endl;
}
}

View File

@@ -210,8 +210,9 @@ T get(const value& v)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[erorr] toml::get specified container size is ", container.size(), "[erorr] toml::get specified container size is ", container.size(),
" but there are ", ar.size(), " elements in toml array."), " but there are ", ar.size(), " elements in toml array."), {
detail::get_region(v), "here")); {std::addressof(detail::get_region(v)), "here"}
}));
} }
std::transform(ar.cbegin(), ar.cend(), container.begin(), std::transform(ar.cbegin(), ar.cend(), container.begin(),
[](const value& x){return ::toml::get<value_type>(x);}); [](const value& x){return ::toml::get<value_type>(x);});
@@ -233,7 +234,9 @@ T get(const value& v)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[erorr] toml::get specified std::pair but there are ", ar.size(), "[erorr] toml::get specified std::pair but there are ", ar.size(),
" elements in toml array."), detail::get_region(v), "here")); " elements in toml array."), {
{std::addressof(detail::get_region(v)), "here"}
}));
} }
return std::make_pair(::toml::get<first_type >(ar.at(0)), return std::make_pair(::toml::get<first_type >(ar.at(0)),
::toml::get<second_type>(ar.at(1))); ::toml::get<second_type>(ar.at(1)));
@@ -264,7 +267,9 @@ T get(const value& v)
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[erorr] toml::get specified std::tuple with ", "[erorr] toml::get specified std::tuple with ",
std::tuple_size<T>::value, "elements, but there are ", ar.size(), std::tuple_size<T>::value, "elements, but there are ", ar.size(),
" elements in toml array."), detail::get_region(v), "here")); " elements in toml array."), {
{std::addressof(detail::get_region(v)), "here"}
}));
} }
return detail::get_tuple_impl<T>(ar, return detail::get_tuple_impl<T>(ar,
detail::make_index_sequence<std::tuple_size<T>::value>{}); detail::make_index_sequence<std::tuple_size<T>::value>{});
@@ -340,8 +345,9 @@ find(const toml::value& v, const toml::key& ky)
if(tab.count(ky) == 0) if(tab.count(ky) == 0)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), detail::get_region(v), "[error] key \"", ky, "\" not found"), {
"in this table")); {std::addressof(detail::get_region(v)), "in this table"}
}));
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
@@ -353,8 +359,9 @@ find(toml::value& v, const toml::key& ky)
if(tab.count(ky) == 0) if(tab.count(ky) == 0)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), detail::get_region(v), "[error] key \"", ky, "\" not found"), {
"in this table")); {std::addressof(detail::get_region(v)), "in this table"}
}));
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
@@ -366,8 +373,9 @@ find(toml::value&& v, const toml::key& ky)
if(tab.count(ky) == 0) if(tab.count(ky) == 0)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), detail::get_region(v), "[error] key \"", ky, "\" not found"), {
"in this table")); {std::addressof(detail::get_region(v)), "in this table"}
}));
} }
return ::toml::get<T>(std::move(tab[ky])); return ::toml::get<T>(std::move(tab[ky]));
} }

View File

@@ -29,13 +29,13 @@ parse_boolean(location<Container>& loc)
else // internal error. else // internal error.
{ {
throw toml::internal_error(format_underline( throw toml::internal_error(format_underline(
"[error] toml::parse_boolean: internal error", reg, "[error] toml::parse_boolean: internal error",
"invalid token")); {{std::addressof(reg), "invalid token"}}));
} }
} }
loc.iter() = first; //rollback loc.iter() = first; //rollback
return err(format_underline("[error] toml::parse_boolean: ", loc, return err(format_underline("[error] toml::parse_boolean: ",
"the next token is not a boolean")); {{std::addressof(loc), "the next token is not a boolean"}}));
} }
template<typename Container> template<typename Container>
@@ -57,14 +57,14 @@ parse_binary_integer(location<Container>& loc)
{ {
throw toml::internal_error(format_underline( throw toml::internal_error(format_underline(
"[error] toml::parse_integer: internal error", "[error] toml::parse_integer: internal error",
token.unwrap(), "invalid token")); {{std::addressof(token.unwrap()), "invalid token"}}));
} }
} }
return ok(std::make_pair(retval, token.unwrap())); return ok(std::make_pair(retval, token.unwrap()));
} }
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error] toml::parse_binary_integer:", loc, return err(format_underline("[error] toml::parse_binary_integer:",
"the next token is not an integer")); {{std::addressof(loc), "the next token is not an integer"}}));
} }
template<typename Container> template<typename Container>
@@ -84,8 +84,8 @@ parse_octal_integer(location<Container>& loc)
return ok(std::make_pair(retval, token.unwrap())); return ok(std::make_pair(retval, token.unwrap()));
} }
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error] toml::parse_octal_integer:", loc, return err(format_underline("[error] toml::parse_octal_integer:",
"the next token is not an integer")); {{std::addressof(loc), "the next token is not an integer"}}));
} }
template<typename Container> template<typename Container>
@@ -105,8 +105,8 @@ parse_hexadecimal_integer(location<Container>& loc)
return ok(std::make_pair(retval, token.unwrap())); return ok(std::make_pair(retval, token.unwrap()));
} }
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error] toml::parse_hexadecimal_integer", loc, return err(format_underline("[error] toml::parse_hexadecimal_integer",
"the next token is not an integer")); {{std::addressof(loc), "the next token is not an integer"}}));
} }
template<typename Container> template<typename Container>
@@ -133,8 +133,8 @@ parse_integer(location<Container>& loc)
return ok(std::make_pair(retval, token.unwrap())); return ok(std::make_pair(retval, token.unwrap()));
} }
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error] toml::parse_integer: ", loc, return err(format_underline("[error] toml::parse_integer: ",
"the next token is not an integer")); {{std::addressof(loc), "the next token is not an integer"}}));
} }
template<typename Container> template<typename Container>
@@ -222,8 +222,8 @@ parse_floating(location<Container>& loc)
return ok(std::make_pair(v, token.unwrap())); return ok(std::make_pair(v, token.unwrap()));
} }
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error] toml::parse_floating: ", loc, return err(format_underline("[error] toml::parse_floating: ",
"the next token is not a float")); {{std::addressof(loc), "the next token is not a float"}}));
} }
template<typename Container, typename Container2> template<typename Container, typename Container2>
@@ -252,8 +252,9 @@ std::string read_utf8_codepoint(const region<Container>& reg,
{ {
std::cerr << format_underline("[warning] " std::cerr << format_underline("[warning] "
"toml::read_utf8_codepoint: codepoints in the range " "toml::read_utf8_codepoint: codepoints in the range "
"[0xD800, 0xDFFF] are not valid UTF-8.", "[0xD800, 0xDFFF] are not valid UTF-8.", {{
loc, "not a valid UTF-8 codepoint") << std::endl; std::addressof(loc), "not a valid UTF-8 codepoint"
}}) << std::endl;
} }
assert(codepoint < 0xD800 || 0xDFFF < codepoint); assert(codepoint < 0xD800 || 0xDFFF < codepoint);
// 1110yyyy 10yxxxxx 10xxxxxx // 1110yyyy 10yxxxxx 10xxxxxx
@@ -267,8 +268,8 @@ std::string read_utf8_codepoint(const region<Container>& reg,
{ {
std::cerr << format_underline("[error] " std::cerr << format_underline("[error] "
"toml::read_utf8_codepoint: input codepoint is too large to " "toml::read_utf8_codepoint: input codepoint is too large to "
"decode as a unicode character.", loc, "decode as a unicode character.", {{std::addressof(loc),
"should be in [0x00..0x10FFFF]") << std::endl; "should be in [0x00..0x10FFFF]"}}) << std::endl;
} }
// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
character += static_cast<unsigned char>(0xF0| codepoint >> 18); character += static_cast<unsigned char>(0xF0| codepoint >> 18);
@@ -280,7 +281,7 @@ std::string read_utf8_codepoint(const region<Container>& reg,
{ {
throw std::range_error(format_underline(concat_to_string("[error] " throw std::range_error(format_underline(concat_to_string("[error] "
"input codepoint (", str, ") is too large to encode as utf-8."), "input codepoint (", str, ") is too large to encode as utf-8."),
reg, "should be in [0x00..0x10FFFF]")); {{std::addressof(reg), "should be in [0x00..0x10FFFF]"}}));
} }
return character; return character;
} }
@@ -291,8 +292,8 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
const auto first = loc.iter(); const auto first = loc.iter();
if(first == loc.end() || *first != '\\') if(first == loc.end() || *first != '\\')
{ {
return err(format_underline("[error]: toml::parse_escape_sequence: ", loc, return err(format_underline("[error]: toml::parse_escape_sequence: ", {{
"the next token is not an escape sequence \"\\\"")); std::addressof(loc), "the next token is not a backslash \"\\\""}}));
} }
++loc.iter(); ++loc.iter();
switch(*loc.iter()) switch(*loc.iter())
@@ -314,7 +315,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
{ {
return err(format_underline("[error] parse_escape_sequence: " return err(format_underline("[error] parse_escape_sequence: "
"invalid token found in UTF-8 codepoint uXXXX.", "invalid token found in UTF-8 codepoint uXXXX.",
loc, token.unwrap_err())); {{std::addressof(loc), token.unwrap_err()}}));
} }
} }
case 'U': case 'U':
@@ -327,16 +328,16 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
{ {
return err(format_underline("[error] parse_escape_sequence: " return err(format_underline("[error] parse_escape_sequence: "
"invalid token found in UTF-8 codepoint Uxxxxxxxx", "invalid token found in UTF-8 codepoint Uxxxxxxxx",
loc, token.unwrap_err())); {{std::addressof(loc), token.unwrap_err()}}));
} }
} }
} }
const auto msg = format_underline("[error] parse_escape_sequence: " const auto msg = format_underline("[error] parse_escape_sequence: "
"unknown escape sequence appeared.", loc, "escape sequence is one of" "unknown escape sequence appeared.", {{std::addressof(loc),
" \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx", {"if you want to write " "escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}},
"backslash as just one backslash, use literal string like:", /* Hints = */{"if you want to write backslash as just one backslash, "
"regex = '<\\i\\c*\\s*>'"}); "use literal string like: regex = '<\\i\\c*\\s*>'"});
loc.iter() = first; loc.iter() = first;
return err(msg); return err(msg);
} }
@@ -359,7 +360,7 @@ parse_ml_basic_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_basic_string: invalid token", "parse_ml_basic_string: invalid token",
inner_loc, "should be \"\"\"")); {{std::addressof(inner_loc), "should be \"\"\""}}));
} }
// immediate newline is ignored (if exists) // immediate newline is ignored (if exists)
/* discard return value */ lex_newline::invoke(inner_loc); /* discard return value */ lex_newline::invoke(inner_loc);
@@ -385,7 +386,7 @@ parse_ml_basic_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_basic_string: unexpected end of region", "parse_ml_basic_string: unexpected end of region",
inner_loc, "not sufficient token")); {{std::addressof(inner_loc), "not sufficient token"}}));
} }
delim = lex_ml_basic_string_delim::invoke(inner_loc); delim = lex_ml_basic_string_delim::invoke(inner_loc);
} }
@@ -412,7 +413,7 @@ parse_basic_string(location<Container>& loc)
if(!quot) if(!quot)
{ {
throw internal_error(format_underline("[error] parse_basic_string: " throw internal_error(format_underline("[error] parse_basic_string: "
"invalid token", inner_loc, "should be \"")); "invalid token", {{std::addressof(inner_loc), "should be \""}}));
} }
std::string retval; std::string retval;
@@ -434,7 +435,7 @@ parse_basic_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_basic_string: unexpected end of region", "parse_ml_basic_string: unexpected end of region",
inner_loc, "not sufficient token")); {{std::addressof(inner_loc), "not sufficient token"}}));
} }
quot = lex_quotation_mark::invoke(inner_loc); quot = lex_quotation_mark::invoke(inner_loc);
} }
@@ -461,7 +462,7 @@ parse_ml_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_literal_string: invalid token", "parse_ml_literal_string: invalid token",
inner_loc, "should be '''")); {{std::addressof(inner_loc), "should be '''"}}));
} }
// immediate newline is ignored (if exists) // immediate newline is ignored (if exists)
/* discard return value */ lex_newline::invoke(inner_loc); /* discard return value */ lex_newline::invoke(inner_loc);
@@ -473,7 +474,7 @@ parse_ml_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_literal_string: invalid token", "parse_ml_literal_string: invalid token",
inner_loc, "should be '''")); {{std::addressof(inner_loc), "should be '''"}}));
} }
return ok(std::make_pair( return ok(std::make_pair(
toml::string(body.unwrap().str(), toml::string_t::literal), toml::string(body.unwrap().str(), toml::string_t::literal),
@@ -500,7 +501,7 @@ parse_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_literal_string: invalid token", "parse_literal_string: invalid token",
inner_loc, "should be '")); {{std::addressof(inner_loc), "should be '"}}));
} }
const auto body = repeat<lex_literal_char, unlimited>::invoke(inner_loc); const auto body = repeat<lex_literal_char, unlimited>::invoke(inner_loc);
@@ -510,7 +511,7 @@ parse_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_literal_string: invalid token", "parse_literal_string: invalid token",
inner_loc, "should be '")); {{std::addressof(inner_loc), "should be '"}}));
} }
return ok(std::make_pair( return ok(std::make_pair(
toml::string(body.unwrap().str(), toml::string_t::literal), toml::string(body.unwrap().str(), toml::string_t::literal),
@@ -531,8 +532,8 @@ parse_string(location<Container>& loc)
if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;} if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;}
if(const auto rslt = parse_basic_string(loc)) {return rslt;} if(const auto rslt = parse_basic_string(loc)) {return rslt;}
if(const auto rslt = parse_literal_string(loc)) {return rslt;} if(const auto rslt = parse_literal_string(loc)) {return rslt;}
return err(format_underline("[error] toml::parse_string: ", loc, return err(format_underline("[error] toml::parse_string: ",
"the next token is not a string")); {{std::addressof(loc), "the next token is not a string"}}));
} }
template<typename Container> template<typename Container>
@@ -547,21 +548,23 @@ parse_local_date(location<Container>& loc)
const auto y = lex_date_fullyear::invoke(inner_loc); const auto y = lex_date_fullyear::invoke(inner_loc);
if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
{ {
const std::string msg = y.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `-`");
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_inner_local_date: invalid year format", "toml::parse_inner_local_date: invalid year format",
inner_loc, y.map_err_or_else([](const std::string& msg) { {{std::addressof(inner_loc), msg}}));
return msg;
}, "should be `-`")));
} }
++inner_loc.iter(); ++inner_loc.iter();
const auto m = lex_date_month::invoke(inner_loc); const auto m = lex_date_month::invoke(inner_loc);
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
{ {
const std::string msg = m.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `-`");
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_date: invalid month format", "toml::parse_local_date: invalid month format",
inner_loc, m.map_err_or_else([](const std::string& msg) { {{std::addressof(inner_loc), msg}}));
return msg;
}, "should be `-`")));
} }
++inner_loc.iter(); ++inner_loc.iter();
const auto d = lex_date_mday::invoke(inner_loc); const auto d = lex_date_mday::invoke(inner_loc);
@@ -569,7 +572,7 @@ parse_local_date(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_date: invalid day format", "toml::parse_local_date: invalid day format",
inner_loc, d.unwrap_err())); {{std::addressof(inner_loc), d.unwrap_err()}}));
} }
return ok(std::make_pair(local_date( return ok(std::make_pair(local_date(
static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)), static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)),
@@ -581,8 +584,8 @@ parse_local_date(location<Container>& loc)
else else
{ {
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error]: toml::parse_local_date: ", loc, return err(format_underline("[error]: toml::parse_local_date: ",
"the next token is not a local_date")); {{std::addressof(loc), "the next token is not a local_date"}}));
} }
} }
@@ -598,21 +601,23 @@ parse_local_time(location<Container>& loc)
const auto h = lex_time_hour::invoke(inner_loc); const auto h = lex_time_hour::invoke(inner_loc);
if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
{ {
const std::string msg = h.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `:`");
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid year format", "toml::parse_local_time: invalid year format",
inner_loc, h.map_err_or_else([](const std::string& msg) { {{std::addressof(inner_loc), msg}}));
return msg;
}, "should be `:`")));
} }
++inner_loc.iter(); ++inner_loc.iter();
const auto m = lex_time_minute::invoke(inner_loc); const auto m = lex_time_minute::invoke(inner_loc);
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
{ {
const std::string msg = m.map_err_or_else(
[](const std::string& msg) {return msg;}, "should be `:`");
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid month format", "toml::parse_local_time: invalid month format",
inner_loc, m.map_err_or_else([](const std::string& msg) { {{std::addressof(inner_loc), msg}}));
return msg;
}, "should be `:`")));
} }
++inner_loc.iter(); ++inner_loc.iter();
const auto s = lex_time_second::invoke(inner_loc); const auto s = lex_time_second::invoke(inner_loc);
@@ -620,7 +625,7 @@ parse_local_time(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid second format", "toml::parse_local_time: invalid second format",
inner_loc, s.unwrap_err())); {{std::addressof(inner_loc), s.unwrap_err()}}));
} }
local_time time( local_time time(
static_cast<std::int8_t>(from_string<int>(h.unwrap().str(), 0)), static_cast<std::int8_t>(from_string<int>(h.unwrap().str(), 0)),
@@ -656,7 +661,7 @@ parse_local_time(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid subsecond format", "toml::parse_local_time: invalid subsecond format",
inner_loc, secfrac.unwrap_err())); {{std::addressof(inner_loc), secfrac.unwrap_err()}}));
} }
} }
return ok(std::make_pair(time, token.unwrap())); return ok(std::make_pair(time, token.unwrap()));
@@ -664,8 +669,8 @@ parse_local_time(location<Container>& loc)
else else
{ {
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error]: toml::parse_local_time: ", loc, return err(format_underline("[error]: toml::parse_local_time: ",
"the next token is not a local_time")); {{std::addressof(loc), "the next token is not a local_time"}}));
} }
} }
@@ -680,25 +685,26 @@ parse_local_datetime(location<Container>& loc)
const auto date = parse_local_date(inner_loc); const auto date = parse_local_date(inner_loc);
if(!date || inner_loc.iter() == inner_loc.end()) if(!date || inner_loc.iter() == inner_loc.end())
{ {
const std::string msg = date.map_err_or_else(
[](const std::string& msg) {return msg;}, "date, not datetime");
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format", "toml::parse_local_datetime: invalid datetime format",
inner_loc, date.map_err_or_else([](const std::string& msg){ {{std::addressof(inner_loc), msg}}));
return msg;
}, "date, not datetime")));
} }
const char delim = *(inner_loc.iter()++); const char delim = *(inner_loc.iter()++);
if(delim != 'T' && delim != 't' && delim != ' ') if(delim != 'T' && delim != 't' && delim != ' ')
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format", "toml::parse_local_datetime: invalid datetime format",
inner_loc, "should be `T` or ` ` (space)")); {{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}));
} }
const auto time = parse_local_time(inner_loc); const auto time = parse_local_time(inner_loc);
if(!time) if(!time)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format", "toml::parse_local_datetime: invalid datetime format",
inner_loc, "invalid time fomrat")); {{std::addressof(inner_loc), "invalid time fomrat"}}));
} }
return ok(std::make_pair( return ok(std::make_pair(
local_datetime(date.unwrap().first, time.unwrap().first), local_datetime(date.unwrap().first, time.unwrap().first),
@@ -707,8 +713,8 @@ parse_local_datetime(location<Container>& loc)
else else
{ {
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error]: toml::parse_local_datetime: ", loc, return err(format_underline("[error]: toml::parse_local_datetime: ",
"the next token is not a local_datetime")); {{std::addressof(loc), "the next token is not a local_datetime"}}));
} }
} }
@@ -723,11 +729,12 @@ parse_offset_datetime(location<Container>& loc)
const auto datetime = parse_local_datetime(inner_loc); const auto datetime = parse_local_datetime(inner_loc);
if(!datetime || inner_loc.iter() == inner_loc.end()) if(!datetime || inner_loc.iter() == inner_loc.end())
{ {
const std::string msg = datetime.map_err_or_else(
[](const std::string& msg){return msg;}, "date, not datetime");
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_offset_datetime: invalid datetime format", "toml::parse_offset_datetime: invalid datetime format",
inner_loc, datetime.map_err_or_else([](const std::string& msg){ {{std::addressof(inner_loc), msg}}));
return msg;
}, "date, not datetime")));
} }
time_offset offset(0, 0); time_offset offset(0, 0);
if(const auto ofs = lex_time_numoffset::invoke(inner_loc)) if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
@@ -748,7 +755,7 @@ parse_offset_datetime(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_offset_datetime: invalid datetime format", "toml::parse_offset_datetime: invalid datetime format",
inner_loc, "should be `Z` or `+HH:MM`")); {{std::addressof(inner_loc), "should be `Z` or `+HH:MM`"}}));
} }
return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset), return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset),
token.unwrap())); token.unwrap()));
@@ -756,8 +763,8 @@ parse_offset_datetime(location<Container>& loc)
else else
{ {
loc.iter() = first; loc.iter() = first;
return err(format_underline("[error]: toml::parse_offset_datetime: ", loc, return err(format_underline("[error]: toml::parse_offset_datetime: ",
"the next token is not a local_datetime")); {{std::addressof(loc), "the next token is not a local_datetime"}}));
} }
} }
@@ -778,8 +785,8 @@ parse_simple_key(location<Container>& loc)
const auto reg = bare.unwrap(); const auto reg = bare.unwrap();
return ok(std::make_pair(reg.str(), reg)); return ok(std::make_pair(reg.str(), reg));
} }
return err(format_underline("[error] toml::parse_simple_key: ", loc, return err(format_underline("[error] toml::parse_simple_key: ",
"the next token is not a simple key")); {{std::addressof(loc), "the next token is not a simple key"}}));
} }
// dotted key become vector of keys // dotted key become vector of keys
@@ -806,7 +813,7 @@ parse_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::detail::parse_key: dotted key contains invalid key", "toml::detail::parse_key: dotted key contains invalid key",
inner_loc, k.unwrap_err())); {{std::addressof(inner_loc), k.unwrap_err()}}));
} }
lex_ws::invoke(inner_loc); lex_ws::invoke(inner_loc);
@@ -821,8 +828,8 @@ parse_key(location<Container>& loc)
else else
{ {
throw internal_error(format_underline("[error] toml::parse_key: " throw internal_error(format_underline("[error] toml::parse_key: "
"dotted key contains invalid key ", inner_loc, "dotted key contains invalid key ",
"should be `.`")); {{std::addressof(inner_loc), "should be `.`"}}));
} }
} }
return ok(std::make_pair(keys, reg)); return ok(std::make_pair(keys, reg));
@@ -835,7 +842,8 @@ parse_key(location<Container>& loc)
return ok(std::make_pair(std::vector<key>(1, smpl.unwrap().first), return ok(std::make_pair(std::vector<key>(1, smpl.unwrap().first),
smpl.unwrap().second)); smpl.unwrap().second));
} }
return err(format_underline("[error] toml::parse_key: ", loc, "is not a valid key")); return err(format_underline("[error] toml::parse_key: ",
{{std::addressof(loc), "is not a valid key"}}));
} }
// forward-decl to implement parse_array and parse_table // forward-decl to implement parse_array and parse_table
@@ -880,22 +888,16 @@ parse_array(location<Container>& loc)
array_start_loc.iter() = first; array_start_loc.iter() = first;
throw syntax_error(format_underline("[error] toml::parse_array: " throw syntax_error(format_underline("[error] toml::parse_array: "
"type of elements should be the same each other.", "type of elements should be the same each other.", {
std::vector<std::pair<region_base const*, std::string>>{ {std::addressof(array_start_loc), "array starts here"},
std::make_pair( {
std::addressof(array_start_loc),
std::string("array starts here")
),
std::make_pair(
std::addressof(get_region(retval.front())), std::addressof(get_region(retval.front())),
std::string("value has type ") + "value has type " + stringize(retval.front().type())
stringize(retval.front().type()) },
), {
std::make_pair(
std::addressof(get_region(val.unwrap())), std::addressof(get_region(val.unwrap())),
std::string("value has different type, ") + "value has different type, " + stringize(val.unwrap().type())
stringize(val.unwrap().type()) }
)
})); }));
} }
retval.push_back(std::move(val.unwrap())); retval.push_back(std::move(val.unwrap()));
@@ -906,9 +908,10 @@ parse_array(location<Container>& loc)
array_start_loc.iter() = first; array_start_loc.iter() = first;
throw syntax_error(format_underline("[error] toml::parse_array: " throw syntax_error(format_underline("[error] toml::parse_array: "
"value having invalid format appeared in an array", "value having invalid format appeared in an array", {
array_start_loc, "array starts here", {std::addressof(array_start_loc), "array starts here"},
loc, "it is not a valid value.")); {std::addressof(loc), "it is not a valid value."}
}));
} }
using lex_array_separator = sequence<maybe<lex_ws>, character<','>>; using lex_array_separator = sequence<maybe<lex_ws>, character<','>>;
@@ -928,14 +931,17 @@ parse_array(location<Container>& loc)
array_start_loc.iter() = first; array_start_loc.iter() = first;
throw syntax_error(format_underline("[error] toml::parse_array:" throw syntax_error(format_underline("[error] toml::parse_array:"
" missing array separator `,` after a value", " missing array separator `,` after a value", {
array_start_loc, "array starts here", loc, "should be `,`")); {std::addressof(array_start_loc), "array starts here"},
{std::addressof(loc), "should be `,`"}
}));
} }
} }
} }
loc.iter() = first; loc.iter() = first;
throw syntax_error(format_underline("[error] toml::parse_array: " throw syntax_error(format_underline("[error] toml::parse_array: "
"array did not closed by `]`", loc, "should be closed")); "array did not closed by `]`",
{{std::addressof(loc), "should be closed"}}));
} }
template<typename Container> template<typename Container>
@@ -953,7 +959,8 @@ parse_key_value_pair(location<Container>& loc)
{ {
loc.iter() = first; loc.iter() = first;
msg = format_underline("[error] toml::parse_key_value_pair: " msg = format_underline("[error] toml::parse_key_value_pair: "
"empty key is not allowed.", loc, "key expected before '='"); "empty key is not allowed.",
{{std::addressof(loc), "key expected before '='"}});
} }
return err(std::move(msg)); return err(std::move(msg));
} }
@@ -968,14 +975,16 @@ parse_key_value_pair(location<Container>& loc)
if(std::find(loc.iter(), line_end, '=') != line_end) if(std::find(loc.iter(), line_end, '=') != line_end)
{ {
msg = format_underline("[error] toml::parse_key_value_pair: " msg = format_underline("[error] toml::parse_key_value_pair: "
"invalid format for key", loc, "invalid character in key", { "invalid format for key",
"Did you forget '.' to separate dotted-key?", {{std::addressof(loc), "invalid character in key"}},
{"Did you forget '.' to separate dotted-key?",
"Allowed characters for bare key are [0-9a-zA-Z_-]."}); "Allowed characters for bare key are [0-9a-zA-Z_-]."});
} }
else // if not, the error is lack of key-value separator. else // if not, the error is lack of key-value separator.
{ {
msg = format_underline("[error] toml::parse_key_value_pair: " msg = format_underline("[error] toml::parse_key_value_pair: "
"missing key-value separator `=`", loc, "should be `=`"); "missing key-value separator `=`",
{{std::addressof(loc), "should be `=`"}});
} }
loc.iter() = first; loc.iter() = first;
return err(std::move(msg)); return err(std::move(msg));
@@ -992,8 +1001,8 @@ parse_key_value_pair(location<Container>& loc)
{ {
loc.iter() = after_kvsp; loc.iter() = after_kvsp;
msg = format_underline("[error] toml::parse_key_value_pair: " msg = format_underline("[error] toml::parse_key_value_pair: "
"missing value after key-value separator '='", loc, "missing value after key-value separator '='",
"expected value, but got nothing"); {{std::addressof(loc), "expected value, but got nothing"}});
} }
else // there is something not a comment/whitespace, so invalid format. else // there is something not a comment/whitespace, so invalid format.
{ {
@@ -1058,7 +1067,7 @@ bool is_valid_forward_table_definition(const value& fwd,
{ {
// table keys always contains all the nodes from the root. // table keys always contains all the nodes from the root.
const auto& tks = tabkeys.unwrap().first; const auto& tks = tabkeys.unwrap().first;
if(std::distance(key_first, key_last) == tks.size() && if(std::size_t(std::distance(key_first, key_last)) == tks.size() &&
std::equal(tks.begin(), tks.end(), key_first)) std::equal(tks.begin(), tks.end(), key_first))
{ {
// the keys are equivalent. it is not allowed. // the keys are equivalent. it is not allowed.
@@ -1079,7 +1088,7 @@ bool is_valid_forward_table_definition(const value& fwd,
// a dotted key starts from the node representing a table in which the // a dotted key starts from the node representing a table in which the
// dotted key belongs to. // dotted key belongs to.
const auto& dks = dotkeys.unwrap().first; const auto& dks = dotkeys.unwrap().first;
if(std::distance(key_curr, key_last) == dks.size() && if(std::size_t(std::distance(key_curr, key_last)) == dks.size() &&
std::equal(dks.begin(), dks.end(), key_curr)) std::equal(dks.begin(), dks.end(), key_curr))
{ {
// the keys are equivalent. it is not allowed. // the keys are equivalent. it is not allowed.
@@ -1122,19 +1131,26 @@ insert_nested_key(table& root, const toml::value& v,
// show special err msg for conflicting table // show special err msg for conflicting table
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of table (\"", "[error] toml::insert_value: array of table (\"",
format_dotted_keys(first, last), "\") cannot insert" format_dotted_keys(first, last),
"ed"), get_region(tab->at(k)), "table already defined", "\") cannot be defined"), {
get_region(v), "this conflicts with the previous table")); {std::addressof(get_region(tab->at(k))),
"table already defined"},
{std::addressof(get_region(v)),
"this conflicts with the previous table"}
}));
} }
else if(!(tab->at(k).is(value_t::Array))) else if(!(tab->at(k).is(value_t::Array)))
{ {
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of table (\"", "[error] toml::insert_value: array of table (\"",
format_dotted_keys(first, last), "\") collides with" format_dotted_keys(first, last), "\") collides with"
" existing value"), get_region(tab->at(k)), " existing value"), {
concat_to_string("this ", tab->at(k).type(), {std::addressof(get_region(tab->at(k))),
" value already exists"), get_region(v), concat_to_string("this ", tab->at(k).type(),
"while inserting this array-of-tables")); " value already exists")},
{std::addressof(get_region(v)),
"while inserting this array-of-tables"}
}));
} }
array& a = tab->at(k).template cast<toml::value_t::Array>(); array& a = tab->at(k).template cast<toml::value_t::Array>();
if(!(a.front().is(value_t::Table))) if(!(a.front().is(value_t::Table)))
@@ -1142,10 +1158,13 @@ insert_nested_key(table& root, const toml::value& v,
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of table (\"", "[error] toml::insert_value: array of table (\"",
format_dotted_keys(first, last), "\") collides with" format_dotted_keys(first, last), "\") collides with"
" existing value"), get_region(tab->at(k)), " existing value"), {
concat_to_string("this ", tab->at(k).type(), {std::addressof(get_region(tab->at(k))),
" value already exists"), get_region(v), concat_to_string("this ", tab->at(k).type(),
"while inserting this array-of-tables")); " value already exists")},
{std::addressof(get_region(v)),
"while inserting this array-of-tables"}
}));
} }
// avoid conflicting array of table like the following. // avoid conflicting array of table like the following.
// ```toml // ```toml
@@ -1167,10 +1186,13 @@ insert_nested_key(table& root, const toml::value& v,
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of table (\"", "[error] toml::insert_value: array of table (\"",
format_dotted_keys(first, last), "\") collides with" format_dotted_keys(first, last), "\") collides with"
" existing array-of-tables"), get_region(tab->at(k)), " existing array-of-tables"), {
concat_to_string("this ", tab->at(k).type(), {std::addressof(get_region(tab->at(k))),
" value has static size"), get_region(v), concat_to_string("this ", tab->at(k).type(),
"appending this to the statically sized array")); " value has static size")},
{std::addressof(get_region(v)),
"appending it to the statically sized array"}
}));
} }
a.push_back(v); a.push_back(v);
return ok(true); return ok(true);
@@ -1191,11 +1213,14 @@ insert_nested_key(table& root, const toml::value& v,
tab->at(k), first, iter, last)) tab->at(k), first, iter, last))
{ {
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: table (\"", "[error] toml::insert_value: table (\"",
format_dotted_keys(first, last), format_dotted_keys(first, last),
"\") already exists."), "\") already exists."), {
get_region(tab->at(k)), "table already exists here", {std::addressof(get_region(tab->at(k))),
get_region(v), "table defined twice")); "table already exists here"},
{std::addressof(get_region(v)),
"table defined twice"}
}));
} }
// to allow the following toml file. // to allow the following toml file.
// [a.b.c] // [a.b.c]
@@ -1217,18 +1242,23 @@ insert_nested_key(table& root, const toml::value& v,
{ {
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: array of tables (\"", "[error] toml::insert_value: array of tables (\"",
format_dotted_keys(first, last), "\") already exists."), format_dotted_keys(first, last), "\") already exists."), {
get_region(tab->at(k)), "array of tables defined here", {std::addressof(get_region(tab->at(k))),
get_region(v), "table conflicts with the previous array" "array of tables defined here"},
" of table")); {std::addressof(get_region(v)),
"table conflicts with the previous array of table"}
}));
} }
else else
{ {
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: value (\"", "[error] toml::insert_value: value (\"",
format_dotted_keys(first, last), "\") already exists."), format_dotted_keys(first, last), "\") already exists."), {
get_region(tab->at(k)), "value already exists here", {std::addressof(get_region(tab->at(k))),
get_region(v), "value defined twice")); "value already exists here"},
{std::addressof(get_region(v)),
"value defined twice"}
}));
} }
} }
tab->insert(std::make_pair(k, v)); tab->insert(std::make_pair(k, v));
@@ -1260,9 +1290,11 @@ insert_nested_key(table& root, const toml::value& v,
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: target (", "[error] toml::insert_value: target (",
format_dotted_keys(first, std::next(iter)), format_dotted_keys(first, std::next(iter)),
") is neither table nor an array of tables"), ") is neither table nor an array of tables"), {
get_region(a.back()), concat_to_string("actual type is ", {std::addressof(get_region(a.back())),
a.back().type()), get_region(v), "inserting this")); concat_to_string("actual type is ", a.back().type())},
{std::addressof(get_region(v)), "inserting this"}
}));
} }
tab = std::addressof(a.back().template cast<value_t::Table>()); tab = std::addressof(a.back().template cast<value_t::Table>());
} }
@@ -1271,9 +1303,11 @@ insert_nested_key(table& root, const toml::value& v,
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
"[error] toml::insert_value: target (", "[error] toml::insert_value: target (",
format_dotted_keys(first, std::next(iter)), format_dotted_keys(first, std::next(iter)),
") is neither table nor an array of tables"), ") is neither table nor an array of tables"), {
get_region(tab->at(k)), concat_to_string("actual type is ", {std::addressof(get_region(tab->at(k))),
tab->at(k).type()), get_region(v), "inserting this")); concat_to_string("actual type is ", tab->at(k).type())},
{std::addressof(get_region(v)), "inserting this"}
}));
} }
} }
} }
@@ -1288,8 +1322,8 @@ parse_inline_table(location<Container>& loc)
table retval; table retval;
if(!(loc.iter() != loc.end() && *loc.iter() == '{')) if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
{ {
return err(format_underline("[error] toml::parse_inline_table: ", loc, return err(format_underline("[error] toml::parse_inline_table: ",
"the next token is not an inline table")); {{std::addressof(loc), "the next token is not an inline table"}}));
} }
++loc.iter(); ++loc.iter();
// it starts from "{". it should be formatted as inline-table // it starts from "{". it should be formatted as inline-table
@@ -1335,13 +1369,14 @@ parse_inline_table(location<Container>& loc)
{ {
throw syntax_error(format_underline("[error] " throw syntax_error(format_underline("[error] "
"toml:::parse_inline_table: missing table separator `,` ", "toml:::parse_inline_table: missing table separator `,` ",
loc, "should be `,`")); {{std::addressof(loc), "should be `,`"}}));
} }
} }
} }
loc.iter() = first; loc.iter() = first;
throw syntax_error(format_underline("[error] toml::parse_inline_table: " throw syntax_error(format_underline("[error] toml::parse_inline_table: "
"inline table did not closed by `}`", loc, "should be closed")); "inline table did not closed by `}`",
{{std::addressof(loc), "should be closed"}}));
} }
template<typename Container> template<typename Container>
@@ -1350,7 +1385,8 @@ result<value, std::string> parse_value(location<Container>& loc)
const auto first = loc.iter(); const auto first = loc.iter();
if(first == loc.end()) if(first == loc.end())
{ {
return err(format_underline("[error] toml::parse_value: input is empty", loc, "")); return err(format_underline("[error] toml::parse_value: input is empty",
{{std::addressof(loc), ""}}));
} }
if(auto r = parse_string (loc)) if(auto r = parse_string (loc))
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
@@ -1374,7 +1410,7 @@ result<value, std::string> parse_value(location<Container>& loc)
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
const auto msg = format_underline("[error] toml::parse_value: " const auto msg = format_underline("[error] toml::parse_value: "
"unknown token appeared", loc, "unknown"); "unknown token appeared", {{std::addressof(loc), "unknown"}});
loc.iter() = first; loc.iter() = first;
return err(msg); return err(msg);
} }
@@ -1391,7 +1427,8 @@ parse_table_key(location<Container>& loc)
if(!open || inner_loc.iter() == inner_loc.end()) if(!open || inner_loc.iter() == inner_loc.end())
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: no `[`", inner_loc, "should be `[`")); "toml::parse_table_key: no `[`",
{{std::addressof(inner_loc), "should be `[`"}}));
} }
// to skip [ a . b . c ] // to skip [ a . b . c ]
// ^----------- this whitespace // ^----------- this whitespace
@@ -1400,7 +1437,8 @@ parse_table_key(location<Container>& loc)
if(!keys) if(!keys)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: invalid key", inner_loc, "not key")); "toml::parse_table_key: invalid key",
{{std::addressof(inner_loc), "not key"}}));
} }
// to skip [ a . b . c ] // to skip [ a . b . c ]
// ^-- this whitespace // ^-- this whitespace
@@ -1409,7 +1447,8 @@ parse_table_key(location<Container>& loc)
if(!close) if(!close)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: no `]`", inner_loc, "should be `]`")); "toml::parse_table_key: no `]`",
{{std::addressof(inner_loc), "should be `]`"}}));
} }
// after [table.key], newline or EOF(empty table) requried. // after [table.key], newline or EOF(empty table) requried.
@@ -1422,7 +1461,7 @@ parse_table_key(location<Container>& loc)
{ {
throw syntax_error(format_underline("[error] " throw syntax_error(format_underline("[error] "
"toml::parse_table_key: newline required after [table.key]", "toml::parse_table_key: newline required after [table.key]",
loc, "expected newline")); {{std::addressof(loc), "expected newline"}}));
} }
} }
return ok(std::make_pair(keys.unwrap().first, token.unwrap())); return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
@@ -1445,23 +1484,24 @@ parse_array_table_key(location<Container>& loc)
if(!open || inner_loc.iter() == inner_loc.end()) if(!open || inner_loc.iter() == inner_loc.end())
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_array_table_key: no `[[`", inner_loc, "toml::parse_array_table_key: no `[[`",
"should be `[[`")); {{std::addressof(inner_loc), "should be `[[`"}}));
} }
lex_ws::invoke(inner_loc); lex_ws::invoke(inner_loc);
const auto keys = parse_key(inner_loc); const auto keys = parse_key(inner_loc);
if(!keys) if(!keys)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_array_table_key: invalid key", inner_loc, "toml::parse_array_table_key: invalid key",
"not key")); {{std::addressof(inner_loc), "not a key"}}));
} }
lex_ws::invoke(inner_loc); lex_ws::invoke(inner_loc);
const auto close = lex_array_table_close::invoke(inner_loc); const auto close = lex_array_table_close::invoke(inner_loc);
if(!close) if(!close)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: no `]]`", inner_loc, "should be `]]`")); "toml::parse_table_key: no `]]`",
{{std::addressof(inner_loc), "should be `]]`"}}));
} }
// after [[table.key]], newline or EOF(empty table) requried. // after [[table.key]], newline or EOF(empty table) requried.
@@ -1472,9 +1512,9 @@ parse_array_table_key(location<Container>& loc)
const auto nl = lex_newline_after_table_key::invoke(loc); const auto nl = lex_newline_after_table_key::invoke(loc);
if(!nl) if(!nl)
{ {
throw syntax_error(format_underline("[error] " throw syntax_error(format_underline("[error] toml::"
"toml::parse_array_table_key: newline required after " "parse_array_table_key: newline required after [[table.key]]",
"[[table.key]]", loc, "expected newline")); {{std::addressof(loc), "expected newline"}}));
} }
} }
return ok(std::make_pair(keys.unwrap().first, token.unwrap())); return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
@@ -1550,8 +1590,8 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
const auto before = loc.iter(); const auto before = loc.iter();
lex_ws::invoke(loc); // skip whitespace lex_ws::invoke(loc); // skip whitespace
const auto msg = format_underline("[error] toml::parse_table: " const auto msg = format_underline("[error] toml::parse_table: "
"invalid line format", loc, concat_to_string( "invalid line format", {{std::addressof(loc), concat_to_string(
"expected newline, but got '", show_char(*loc.iter()), "'.")); "expected newline, but got '", show_char(*loc.iter()), "'.")}});
loc.iter() = before; loc.iter() = before;
return err(msg); return err(msg);
} }
@@ -1621,7 +1661,7 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
continue; continue;
} }
return err(format_underline("[error]: toml::parse_toml_file: " return err(format_underline("[error]: toml::parse_toml_file: "
"unknown line appeared", loc, "unknown format")); "unknown line appeared", {{std::addressof(loc), "unknown format"}}));
} }
return ok(data); return ok(data);
} }

View File

@@ -237,149 +237,6 @@ struct region final : public region_base
const_iterator first_, last_; const_iterator first_, last_;
}; };
// to show a better error message.
inline std::string format_underline(const std::string& message,
const region_base& reg, const std::string& comment_for_underline,
std::vector<std::string> helps = {})
{
#ifdef _WIN32
const auto newline = "\r\n";
#else
const char newline = '\n';
#endif
const auto line = reg.line();
const auto line_number = reg.line_num();
std::string retval;
retval += message;
retval += newline;
retval += " --> ";
retval += reg.name();
retval += newline;
retval += ' ';
retval += line_number;
retval += " | ";
retval += line;
retval += newline;
retval += make_string(line_number.size() + 1, ' ');
retval += " | ";
retval += make_string(reg.before(), ' ');
if(reg.size() == 1)
{
// invalid
// ^------
retval += '^';
retval += make_string(reg.after(), '-');
}
else
{
// invalid
// ~~~~~~~
retval += make_string(reg.size(), '~');
}
retval += ' ';
retval += comment_for_underline;
if(helps.size() != 0)
{
retval += newline;
retval += make_string(line_number.size() + 1, ' ');
retval += " | ";
for(const auto help : helps)
{
retval += newline;
retval += "Hint: ";
retval += help;
}
}
return retval;
}
// to show a better error message.
inline std::string format_underline(const std::string& message,
const region_base& reg1, const std::string& comment_for_underline1,
const region_base& reg2, const std::string& comment_for_underline2,
std::vector<std::string> helps = {})
{
#ifdef _WIN32
const auto newline = "\r\n";
#else
const char newline = '\n';
#endif
const auto line1 = reg1.line();
const auto line_number1 = reg1.line_num();
const auto line2 = reg2.line();
const auto line_number2 = reg2.line_num();
const auto line_num_width =
std::max(line_number1.size(), line_number2.size());
std::ostringstream retval;
retval << message << newline;
retval << " --> " << reg1.name() << newline;
// ---------------------------------------
retval << ' ' << std::setw(line_num_width) << line_number1;
retval << " | " << line1 << newline;
retval << make_string(line_num_width + 1, ' ');
retval << " | ";
retval << make_string(reg1.before(), ' ');
if(reg1.size() == 1)
{
// invalid
// ^------
retval << '^';
retval << make_string(reg1.after(), '-');
}
else
{
// invalid
// ~~~~~~~
retval << make_string(reg1.size(), '~');
}
retval << ' ';
retval << comment_for_underline1 << newline;
// ---------------------------------------
if(reg2.name() != reg1.name())
{
retval << " --> " << reg2.name() << newline;
}
else
{
retval << " ..." << newline;
}
retval << ' ' << std::setw(line_num_width) << line_number2;
retval << " | " << line2 << newline;
retval << make_string(line_num_width + 1, ' ');
retval << " | ";
retval << make_string(reg2.before(), ' ');
if(reg2.size() == 1)
{
// invalid
// ^------
retval << '^';
retval << make_string(reg2.after(), '-');
}
else
{
// invalid
// ~~~~~~~
retval << make_string(reg2.size(), '~');
}
retval << ' ';
retval << comment_for_underline2;
if(helps.size() != 0)
{
retval << newline;
retval << make_string(line_num_width + 1, ' ');
retval << " | ";
for(const auto help : helps)
{
retval << newline;
retval << "Hint: ";
retval << help;
}
}
return retval.str();
}
// to show a better error message. // to show a better error message.
inline std::string format_underline(const std::string& message, inline std::string format_underline(const std::string& message,
std::vector<std::pair<region_base const*, std::string>> reg_com, std::vector<std::pair<region_base const*, std::string>> reg_com,
@@ -408,10 +265,11 @@ inline std::string format_underline(const std::string& message,
{ {
if(i!=0 && reg_com.at(i-1).first->name() == reg_com.at(i).first->name()) if(i!=0 && reg_com.at(i-1).first->name() == reg_com.at(i).first->name())
{ {
retval << " ..." << newline; retval << newline << " ..." << newline;
} }
else else
{ {
if(i != 0) {retval << newline;}
retval << " --> " << reg_com.at(i).first->name() << newline; retval << " --> " << reg_com.at(i).first->name() << newline;
} }
@@ -439,7 +297,7 @@ inline std::string format_underline(const std::string& message,
} }
retval << ' '; retval << ' ';
retval << comment << newline; retval << comment;
} }
if(helps.size() != 0) if(helps.size() != 0)
@@ -457,7 +315,6 @@ inline std::string format_underline(const std::string& message,
return retval.str(); return retval.str();
} }
} // detail } // detail
} // toml } // toml
#endif// TOML11_REGION_H #endif// TOML11_REGION_H

View File

@@ -5,6 +5,7 @@
#include "value.hpp" #include "value.hpp"
#include "lexer.hpp" #include "lexer.hpp"
#include <limits> #include <limits>
#include <cstdio>
namespace toml namespace toml
{ {
@@ -30,13 +31,12 @@ struct serializer
} }
std::string operator()(const toml::floating f) const std::string operator()(const toml::floating f) const
{ {
std::string token = [=] { const auto fmt = "%.*g";
// every float value needs decimal point (or exponent). const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
std::ostringstream oss; std::vector<char> buf(bsz + 1, '\0'); // +1 for null character(\0)
oss << std::setprecision(float_prec_) << std::showpoint << f; std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
return oss.str();
}();
std::string token(buf.begin(), buf.end());
if(token.back() == '.') // 1. => 1.0 if(token.back() == '.') // 1. => 1.0
{ {
token += '0'; token += '0';

View File

@@ -8,32 +8,38 @@ namespace toml
{ {
template<typename T> template<typename T>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(T&& x) inline value to_toml(T&& x)
{ {
return value(std::forward<T>(x)); return value(std::forward<T>(x));
} }
template<typename T> template<typename T>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(T&& x, string_t kind) inline value to_toml(T&& x, string_t kind)
{ {
return value(std::forward<T>(x), kind); return value(std::forward<T>(x), kind);
} }
TOML11_MARK_AS_DEPRECATED
inline value to_toml(local_date d, local_time t) inline value to_toml(local_date d, local_time t)
{ {
return value(local_datetime(d, t)); return value(local_datetime(d, t));
} }
TOML11_MARK_AS_DEPRECATED
inline value to_toml(local_date d, local_time t, time_offset ofs) inline value to_toml(local_date d, local_time t, time_offset ofs)
{ {
return value(offset_datetime(d, t, ofs)); return value(offset_datetime(d, t, ofs));
} }
template<typename ... Ts> template<typename ... Ts>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(Ts&& ... xs) inline value to_toml(Ts&& ... xs)
{ {
return value(toml::array{toml::value(std::forward<Ts>(xs)) ... }); return value(toml::array{toml::value(std::forward<Ts>(xs)) ... });
} }
TOML11_MARK_AS_DEPRECATED
inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs) inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs)
{ {
return value(toml::table(xs.begin(), xs.end())); return value(toml::table(xs.begin(), xs.end()));

View File

@@ -7,6 +7,16 @@
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#if __cplusplus >= 201402L
# define TOML11_MARK_AS_DEPRECATED [[deprecated]]
#elif defined(__GNUC__)
# define TOML11_MARK_AS_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
# define TOML11_MARK_AS_DEPRECATED __declspec(deprecated)
#else
# define TOML11_MARK_AS_DEPRECATED
#endif
namespace toml namespace toml
{ {

View File

@@ -693,9 +693,11 @@ typename detail::toml_default_type<T>::type& value::cast() &
{ {
if(T != this->type_) if(T != this->type_)
{ {
throw type_error(format_underline(concat_to_string( throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", T), *region_info_, "[error] toml::value bad_cast to ", T), {
concat_to_string("the actual type is ", this->type_))); {this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}));
} }
return switch_cast<T>::invoke(*this); return switch_cast<T>::invoke(*this);
} }
@@ -704,9 +706,11 @@ typename detail::toml_default_type<T>::type const& value::cast() const&
{ {
if(T != this->type_) if(T != this->type_)
{ {
throw type_error(format_underline(concat_to_string( throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", T), *region_info_, "[error] toml::value bad_cast to ", T), {
concat_to_string("the actual type is ", this->type_))); {this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}));
} }
return switch_cast<T>::invoke(*this); return switch_cast<T>::invoke(*this);
} }
@@ -715,9 +719,11 @@ typename detail::toml_default_type<T>::type&& value::cast() &&
{ {
if(T != this->type_) if(T != this->type_)
{ {
throw type_error(format_underline(concat_to_string( throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", T), *region_info_, "[error] toml::value bad_cast to ", T), {
concat_to_string("the actual type is ", this->type_))); {this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}));
} }
return switch_cast<T>::invoke(std::move(*this)); return switch_cast<T>::invoke(std::move(*this));
} }
@@ -800,22 +806,38 @@ inline bool operator>=(const toml::value& lhs, const toml::value& rhs)
return !(lhs < rhs); return !(lhs < rhs);
} }
inline std::string format_error(const std::string& err_msg, namespace detail
const toml::value& v, const std::string& comment,
std::vector<std::string> hints = {})
{ {
return detail::format_underline(err_msg, detail::get_region(v), comment, inline std::string format_error_impl(const std::string& err_msg,
std::move(hints)); std::vector<std::pair<region_base const*, std::string>> val,
std::vector<std::string> hints)
{
return format_underline(err_msg, std::move(val), std::move(hints));
}
inline std::string format_error_impl(const std::string& err_msg,
std::vector<std::pair<region_base const*, std::string>> val)
{
return format_underline(err_msg, std::move(val));
} }
inline std::string format_error(const std::string& err_msg, template<typename ... Ts>
const toml::value& v1, const std::string& comment1, std::string format_error_impl(const std::string& err_msg,
const toml::value& v2, const std::string& comment2, std::vector<std::pair<region_base const*, std::string>> val,
std::vector<std::string> hints = {}) const toml::value& v, const std::string& comment,
Ts&& ... args)
{ {
return detail::format_underline(err_msg, detail::get_region(v1), comment1, val.push_back(std::make_pair(std::addressof(get_region(v)), comment));
detail::get_region(v2), comment2, return format_error_impl(err_msg, std::move(val), std::forward<Ts>(args)...);
std::move(hints)); }
} // detail
template<typename ... Ts>
std::string format_error(const std::string& err_msg, Ts&& ... args)
{
std::vector<std::pair<detail::region_base const*, std::string>> val;
val.reserve(sizeof...(args) / 2);
return detail::format_error_impl(err_msg, std::move(val),
std::forward<Ts>(args)...);
} }
template<typename Visitor> template<typename Visitor>