Compare commits

..

11 Commits

Author SHA1 Message Date
Toru Niina
5dfdbe4bff Merge pull request #20 from ToruNiina/format-error
add an extra parameter `hints` to format_error
2018-12-27 20:34:53 +09:00
Toru Niina
4584eeb57a Merge pull request #19 from ToruNiina/find-default-type
add default template arg to toml::find
2018-12-27 20:34:36 +09:00
ToruNiina
aa67069387 move hints to the internal function 2018-12-27 16:32:20 +09:00
ToruNiina
ee3424ad51 add an extra parameter hints to format_error 2018-12-27 16:26:23 +09:00
ToruNiina
17def14ab6 add default template arg to toml::find
in most of the use cases, toml::value is used (to show error message).
2018-12-27 15:58:50 +09:00
Toru Niina
b5b8830c29 Merge pull request #17 from ToruNiina/hotfix
fix the error with BOM and end of file w/o newline
2018-12-24 16:37:10 +09:00
ToruNiina
87a5c844c2 add test cases for the end-of-file problems 2018-12-24 16:02:32 +09:00
ToruNiina
11c7ee4501 fix the case of file w/o newline at the end
toml::parse failed with the file that contains whitespace or comment at
the end of file without newline. this commit fixes the error.
2018-12-24 16:00:33 +09:00
ToruNiina
d24a188d4c fix the error while reading BOM.
remove possible UB because of the use-after-move.
2018-12-24 15:06:26 +09:00
Toru Niina
29876221f8 Merge pull request #15 from ToruNiina/performance
speedup by removing needless format_underline
2018-12-23 18:30:19 +09:00
ToruNiina
7c03c446fe speedup by removing needless format_underline
drastical speedup for long toml files
2018-12-23 15:22:12 +09:00
4 changed files with 538 additions and 69 deletions

View File

@@ -194,3 +194,469 @@ BOOST_AUTO_TEST_CASE(test_hard_example)
BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) == BOOST_CHECK(toml::get<std::vector<std::string>>(bit.at("multi_line_array")) ==
expected_multi_line_array); expected_multi_line_array);
} }
// ---------------------------------------------------------------------------
// after here, the test codes generate the content of a file.
BOOST_AUTO_TEST_CASE(test_file_with_BOM)
{
{
const std::string table(
"\xEF\xBB\xBF" // BOM
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss, "test_file_with_BOM.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"\xEF\xBB\xBF" // BOM
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss, "test_file_with_BOM_CRLF.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
}
BOOST_AUTO_TEST_CASE(test_file_without_newline_at_the_end_of_file)
{
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\""
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\""
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_CRLF.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\" # comment"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\" # comment"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\" \t"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_ws.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\" \t"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_file_without_newline_at_the_end_of_file_ws.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
}
BOOST_AUTO_TEST_CASE(test_files_end_with_comment)
{
// comment w/o newline
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"# comment"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"# comment\n"
"# one more comment"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
// comment w/ newline
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"# comment\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"# comment\n"
"# one more comment\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
// CRLF version
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"# comment"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"# comment\r\n"
"# one more comment"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"# comment\r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"# comment\r\n"
"# one more comment\r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_comment.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
}
BOOST_AUTO_TEST_CASE(test_files_end_with_empty_lines)
{
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"\n"
"\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
// with whitespaces
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
" \n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
" \n"
" \n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
"\n"
" \n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
" \n"
"\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
// with whitespaces but no newline
{
const std::string table(
"key = \"value\"\n"
"[table]\n"
"key = \"value\"\n"
" "
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
// CRLF
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"\r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"\r\n"
"\r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
// with whitespaces
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
" \r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
"\r\n"
" \r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
" \r\n"
"\r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
" \r\n"
" \r\n"
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
{
const std::string table(
"key = \"value\"\r\n"
"[table]\r\n"
"key = \"value\"\r\n"
" "
);
std::istringstream iss(table);
const auto data = toml::parse(iss,
"test_files_end_with_newline.toml");
BOOST_CHECK_EQUAL(toml::get <std::string>(data.at("key")), "value");
BOOST_CHECK_EQUAL(toml::find<std::string>(data.at("table"), "key"), "value");
}
}

View File

@@ -295,7 +295,7 @@ T get(const toml::value& v)
// ============================================================================ // ============================================================================
// find and get // find and get
template<typename T> template<typename T = ::toml::value>
decltype(::toml::get<T>(std::declval<const ::toml::value&>())) decltype(::toml::get<T>(std::declval<const ::toml::value&>()))
find(const toml::table& tab, const toml::key& ky, find(const toml::table& tab, const toml::key& ky,
std::string tablename = "unknown table") std::string tablename = "unknown table")
@@ -307,7 +307,7 @@ find(const toml::table& tab, const toml::key& ky,
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
template<typename T> template<typename T = ::toml::value>
decltype(::toml::get<T>(std::declval<::toml::value&>())) decltype(::toml::get<T>(std::declval<::toml::value&>()))
find(toml::table& tab, const toml::key& ky, find(toml::table& tab, const toml::key& ky,
std::string tablename = "unknown table") std::string tablename = "unknown table")
@@ -319,7 +319,7 @@ find(toml::table& tab, const toml::key& ky,
} }
return ::toml::get<T>(tab[ky]); return ::toml::get<T>(tab[ky]);
} }
template<typename T> template<typename T = ::toml::value>
decltype(::toml::get<T>(std::declval<::toml::value&&>())) decltype(::toml::get<T>(std::declval<::toml::value&&>()))
find(toml::table&& tab, const toml::key& ky, find(toml::table&& tab, const toml::key& ky,
std::string tablename = "unknown table") std::string tablename = "unknown table")
@@ -332,7 +332,7 @@ find(toml::table&& tab, const toml::key& ky,
return ::toml::get<T>(std::move(tab[ky])); return ::toml::get<T>(std::move(tab[ky]));
} }
template<typename T> template<typename T = ::toml::value>
decltype(::toml::get<T>(std::declval<const ::toml::value&>())) decltype(::toml::get<T>(std::declval<const ::toml::value&>()))
find(const toml::value& v, const toml::key& ky) find(const toml::value& v, const toml::key& ky)
{ {
@@ -345,7 +345,7 @@ find(const toml::value& v, const toml::key& ky)
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
template<typename T> template<typename T = ::toml::value>
decltype(::toml::get<T>(std::declval<::toml::value&>())) decltype(::toml::get<T>(std::declval<::toml::value&>()))
find(toml::value& v, const toml::key& ky) find(toml::value& v, const toml::key& ky)
{ {
@@ -358,7 +358,7 @@ find(toml::value& v, const toml::key& ky)
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
template<typename T> template<typename T = ::toml::value>
decltype(::toml::get<T>(std::declval<::toml::value&&>())) decltype(::toml::get<T>(std::declval<::toml::value&&>()))
find(toml::value&& v, const toml::key& ky) find(toml::value&& v, const toml::key& ky)
{ {

View File

@@ -34,8 +34,8 @@ parse_boolean(location<Container>& loc)
} }
} }
loc.iter() = first; //rollback loc.iter() = first; //rollback
return err(format_underline("[error] toml::parse_boolean", loc, return err(std::string("[error] toml::parse_boolean: "
"token is not boolean", {"boolean is `true` or `false`"})); "the next token is not a boolean"));
} }
template<typename Container> template<typename Container>
@@ -63,8 +63,8 @@ parse_binary_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_binary_integer", loc, return err(std::string("[error] toml::parse_binary_integer:"
"token is not binary integer", {"binary integer is like: 0b0011"})); "the next token is not an integer"));
} }
template<typename Container> template<typename Container>
@@ -84,9 +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(std::string("[error] toml::parse_octal_integer:"
return err(format_underline("[error] toml::parse_octal_integer", loc, "the next token is not an integer"));
"token is not octal integer", {"octal integer is like: 0o775"}));
} }
template<typename Container> template<typename Container>
@@ -106,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(std::string("[error] toml::parse_hexadecimal_integer"
"token is not hex integer", {"hex integer is like: 0xC0FFEE"})); "the next token is not an integer"));
} }
template<typename Container> template<typename Container>
@@ -134,10 +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(std::string("[error] toml::parse_integer: "
"token is not integer", {"integer is like: +42", "the next token is not an integer"));
"hex integer is like: 0xC0FFEE", "octal integer is like: 0o775",
"binary integer is like: 0b0011"}));
} }
template<typename Container> template<typename Container>
@@ -225,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(std::string("[error] toml::parse_floating: "
"token is not a float", {"floating point is like: -3.14e+1"})); "the next token is not a float"));
} }
template<typename Container> template<typename Container>
@@ -286,9 +283,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]: " return err(std::string("[error]: toml::parse_escape_sequence: "
"toml::parse_escape_sequence: location does not points \"\\\"", "the next token is not an escape sequence \"\\\""));
loc, "should be \"\\\""));
} }
++loc.iter(); ++loc.iter();
switch(*loc.iter()) switch(*loc.iter())
@@ -527,8 +523,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: not a string", return err(std::string("[error] toml::parse_string: "
loc, "not a string")); "the next token is not a string"));
} }
template<typename Container> template<typename Container>
@@ -576,11 +572,9 @@ parse_local_date(location<Container>& loc)
} }
else else
{ {
auto msg = format_underline("[error]: toml::parse_local_date: "
"invalid format", loc, token.unwrap_err(),
{"local date is like: 1979-05-27"});
loc.iter() = first; loc.iter() = first;
return err(std::move(msg)); return err(std::string("[error]: toml::parse_local_date: "
"the next token is not a local_date"));
} }
} }
@@ -661,11 +655,9 @@ parse_local_time(location<Container>& loc)
} }
else else
{ {
auto msg = format_underline("[error]: toml::parse_local_time: "
"invalid format", loc, token.unwrap_err(),
{"local time is like: 00:32:00.999999"});
loc.iter() = first; loc.iter() = first;
return err(std::move(msg)); return err(std::string("[error]: toml::parse_local_time: "
"the next token is not a local_time"));
} }
} }
@@ -706,11 +698,9 @@ parse_local_datetime(location<Container>& loc)
} }
else else
{ {
auto msg = format_underline("[error]: toml::parse_local_datetime: "
"invalid format", loc, token.unwrap_err(),
{"local datetime is like: 1979-05-27T00:32:00.999999"});
loc.iter() = first; loc.iter() = first;
return err(std::move(msg)); return err(std::string("[error]: toml::parse_local_datetime: "
"the next token is not a local_datetime"));
} }
} }
@@ -757,12 +747,9 @@ parse_offset_datetime(location<Container>& loc)
} }
else else
{ {
auto msg = format_underline("[error]: toml::parse_offset_datetime: "
"invalid format", loc, token.unwrap_err(),
{"offset datetime is like: 1979-05-27T00:32:00-07:00",
"or in UTC (w/o offset) : 1979-05-27T00:32:00Z"});
loc.iter() = first; loc.iter() = first;
return err(std::move(msg)); return err(std::string("[error]: toml::parse_offset_datetime: "
"the next token is not a local_datetime"));
} }
} }
@@ -781,8 +768,8 @@ result<key, std::string> parse_simple_key(location<Container>& loc)
{ {
return ok(bare.unwrap().str()); return ok(bare.unwrap().str());
} }
return err(format_underline("[error] toml::parse_simple_key: " return err(std::string("[error] toml::parse_simple_key: "
"the next token is not a simple key", loc, "not a key")); "the next token is not a simple key"));
} }
// dotted key become vector of keys // dotted key become vector of keys
@@ -835,8 +822,8 @@ result<std::vector<key>, std::string> parse_key(location<Container>& loc)
{ {
return ok(std::vector<key>(1, smpl.unwrap())); return ok(std::vector<key>(1, smpl.unwrap()));
} }
return err(format_underline("toml::parse_key: the next token is not a key", return err(std::string("[error] toml::parse_key: "
loc, "not a key")); "the next token is not a key"));
} }
// forward-decl to implement parse_array and parse_table // forward-decl to implement parse_array and parse_table
@@ -854,8 +841,7 @@ parse_array(location<Container>& loc)
} }
if(*loc.iter() != '[') if(*loc.iter() != '[')
{ {
return err(format_underline("[error] toml::parse_array: " return err("[error] toml::parse_array: token is not an array");
"token is not an array", loc, "should be ["));
} }
++loc.iter(); ++loc.iter();
@@ -903,13 +889,13 @@ parse_array(location<Container>& loc)
} }
else else
{ {
return err(format_underline("[error] toml::parse_array: " throw syntax_error(format_underline("[error] toml::parse_array:"
"missing array separator `,`", loc, "should be `,`")); " missing array separator `,`", loc, "should be `,`"));
} }
} }
} }
loc.iter() = first; loc.iter() = first;
return err(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 `]`", loc, "should be closed"));
} }
@@ -1181,10 +1167,11 @@ 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: " return err(std::string("[error] toml::parse_inline_table: "
"the next token is not an inline table", loc, "not `{`.")); "the next token is not an inline table"));
} }
++loc.iter(); ++loc.iter();
// it starts from "{". it should be formatted as inline-table
while(loc.iter() != loc.end()) while(loc.iter() != loc.end())
{ {
maybe<lex_ws>::invoke(loc); maybe<lex_ws>::invoke(loc);
@@ -1224,13 +1211,14 @@ parse_inline_table(location<Container>& loc)
} }
else else
{ {
return err(format_underline("[error] toml:::parse_inline_table:" throw syntax_error(format_underline("[error] "
" missing table separator `,` ", loc, "should be `,`")); "toml:::parse_inline_table: missing table separator `,` ",
loc, "should be `,`"));
} }
} }
} }
loc.iter() = first; loc.iter() = first;
return err(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 `}`", loc, "should be closed"));
} }
@@ -1357,7 +1345,7 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
return err(std::string("toml::parse_ml_table: input is empty")); return err(std::string("toml::parse_ml_table: input is empty"));
} }
// XXX at lest one newline is needed // XXX at lest one newline is needed.
using skip_line = repeat< using skip_line = repeat<
sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>; sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>;
skip_line::invoke(loc); skip_line::invoke(loc);
@@ -1377,6 +1365,7 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
loc.iter() = before; loc.iter() = before;
return ok(tab); return ok(tab);
} }
if(const auto kv = parse_key_value_pair(loc)) if(const auto kv = parse_key_value_pair(loc))
{ {
const std::vector<key>& keys = kv.unwrap().first; const std::vector<key>& keys = kv.unwrap().first;
@@ -1393,6 +1382,17 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
return err(kv.unwrap_err()); return err(kv.unwrap_err());
} }
// comment lines are skipped by the above function call.
// However, since the `skip_line` requires at least 1 newline, it fails
// if the file ends with ws and/or comment without newline.
// `skip_line` matches `ws? + comment? + newline`, not `ws` or `comment`
// itself. To skip the last ws and/or comment, call lexers.
// It does not matter if these fails, so the return value is discarded.
lex_ws::invoke(loc);
lex_comment::invoke(loc);
// skip_line is (whitespace? comment? newline)_{1,}. multiple empty lines
// and comments after the last key-value pairs are allowed.
const auto newline = skip_line::invoke(loc); const auto newline = skip_line::invoke(loc);
if(!newline && loc.iter() != loc.end()) if(!newline && loc.iter() != loc.end())
{ {
@@ -1405,11 +1405,10 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
return err(msg); return err(msg);
} }
// comment lines are skipped by the above function call. // the skip_lines only matches with lines that includes newline.
// However, if the file ends with comment without newline, // to skip the last line that includes comment and/or whitespace
// it might cause parsing error because skip_line matches // but no newline, call them one more time.
// `comment + newline`, not `comment` itself. to skip the lex_ws::invoke(loc);
// last comment, call lex_comment one more time.
lex_comment::invoke(loc); lex_comment::invoke(loc);
} }
return ok(tab); return ok(tab);
@@ -1498,10 +1497,10 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
// be compared to char. However, since we are always out of luck, we need to // be compared to char. However, since we are always out of luck, we need to
// check our chars are equivalent to BOM. To do this, first we need to // check our chars are equivalent to BOM. To do this, first we need to
// convert char to unsigned char to guarantee the comparability. // convert char to unsigned char to guarantee the comparability.
if(letters.size() >= 3) if(loc.source()->size() >= 3)
{ {
std::array<unsigned char, 3> BOM; std::array<unsigned char, 3> BOM;
std::memcpy(BOM.data(), letters.data(), 3); std::memcpy(BOM.data(), loc.source()->data(), 3);
if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF) if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
{ {
loc.iter() += 3; // BOM found. skip. loc.iter() += 3; // BOM found. skip.

View File

@@ -801,17 +801,21 @@ inline bool operator>=(const toml::value& lhs, const toml::value& rhs)
} }
inline std::string format_error(const std::string& err_msg, inline std::string format_error(const std::string& err_msg,
const toml::value& v, const std::string& comment) const toml::value& v, const std::string& comment,
std::vector<std::string> hints = {})
{ {
return detail::format_underline(err_msg, detail::get_region(v), comment); return detail::format_underline(err_msg, detail::get_region(v), comment,
std::move(hints));
} }
inline std::string format_error(const std::string& err_msg, inline std::string format_error(const std::string& err_msg,
const toml::value& v1, const std::string& comment1, const toml::value& v1, const std::string& comment1,
const toml::value& v2, const std::string& comment2) const toml::value& v2, const std::string& comment2,
std::vector<std::string> hints = {})
{ {
return detail::format_underline(err_msg, detail::get_region(v1), comment1, return detail::format_underline(err_msg, detail::get_region(v1), comment1,
detail::get_region(v2), comment2); detail::get_region(v2), comment2,
std::move(hints));
} }
}// toml }// toml