mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-18 02:08:09 +08:00
perf: remove err-msg from combinator
Generate error message in `parse_something()`, not in `lex_something`. Since the error message generated by `lex_something` is too difficult to read for humans, I've disabled the error message generation for the sake of efficiency (it takes time to generate error message that will never be read). I think now the error message generation itself safely can be removed from combinators. At this stage, `lex_something` does not need to return `result<T, E>` because all the error type would be discarded. Now it is turned out that returing `optional<T>` from lex_* is enough. Maybe later I would change the return type itself, but currently I changed the error type from std::string to char because implementing optional takes time and effort. It makes the parsing process a bit faster.
This commit is contained in:
@@ -56,24 +56,19 @@ struct character
|
|||||||
static constexpr char target = C;
|
static constexpr char target = C;
|
||||||
|
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
if(loc.iter() == loc.end()) {return err('\0');}
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
|
|
||||||
const char c = *(loc.iter());
|
const char c = *(loc.iter());
|
||||||
if(c != target)
|
if(c != target)
|
||||||
{
|
{
|
||||||
if(msg)
|
return err(c);
|
||||||
{
|
|
||||||
return err(concat_to_string("expected '", show_char(target),
|
|
||||||
"' but got '", show_char(c), "'."));
|
|
||||||
}
|
|
||||||
return err("");
|
|
||||||
}
|
}
|
||||||
loc.advance(); // update location
|
loc.advance(); // update location
|
||||||
|
|
||||||
@@ -94,25 +89,19 @@ struct in_range
|
|||||||
static constexpr char lower = Low;
|
static constexpr char lower = Low;
|
||||||
|
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
if(loc.iter() == loc.end()) {return err('\0');}
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
|
|
||||||
const char c = *(loc.iter());
|
const char c = *(loc.iter());
|
||||||
if(c < lower || upper < c)
|
if(c < lower || upper < c)
|
||||||
{
|
{
|
||||||
if(msg)
|
return err(c);
|
||||||
{
|
|
||||||
return err(concat_to_string("expected character in range "
|
|
||||||
"[", show_char(lower), ", ", show_char(upper), "] but got ",
|
|
||||||
"'", show_char(c), "'."));
|
|
||||||
}
|
|
||||||
return err("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loc.advance();
|
loc.advance();
|
||||||
@@ -128,25 +117,20 @@ template<typename Combinator>
|
|||||||
struct exclude
|
struct exclude
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
if(loc.iter() == loc.end()) {return err("not sufficient characters");}
|
if(loc.iter() == loc.end()) {return err('\0');}
|
||||||
auto first = loc.iter();
|
auto first = loc.iter();
|
||||||
|
|
||||||
auto rslt = Combinator::invoke(loc, msg);
|
auto rslt = Combinator::invoke(loc);
|
||||||
if(rslt.is_ok())
|
if(rslt.is_ok())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
if(msg)
|
return err(*first);
|
||||||
{
|
|
||||||
return err(concat_to_string("invalid pattern appeared ",
|
|
||||||
rslt.unwrap().str()));
|
|
||||||
}
|
|
||||||
return err("");
|
|
||||||
}
|
}
|
||||||
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
|
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
|
||||||
return ok(region<Cont>(loc, first, loc.iter()));
|
return ok(region<Cont>(loc, first, loc.iter()));
|
||||||
@@ -158,13 +142,13 @@ template<typename Combinator>
|
|||||||
struct maybe
|
struct maybe
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
const auto rslt = Combinator::invoke(loc, msg);
|
const auto rslt = Combinator::invoke(loc);
|
||||||
if(rslt.is_ok())
|
if(rslt.is_ok())
|
||||||
{
|
{
|
||||||
return rslt;
|
return rslt;
|
||||||
@@ -180,36 +164,35 @@ template<typename Head, typename ... Tail>
|
|||||||
struct sequence<Head, Tail...>
|
struct sequence<Head, Tail...>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
const auto rslt = Head::invoke(loc, msg);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first, msg);
|
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from the above function only, recursively.
|
// called from the above function only, recursively.
|
||||||
template<typename Cont, typename Iterator>
|
template<typename Cont, typename Iterator>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first,
|
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
||||||
const bool msg = false)
|
|
||||||
{
|
{
|
||||||
const auto rslt = Head::invoke(loc, msg);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
return err(rslt.unwrap_err());
|
return err(rslt.unwrap_err());
|
||||||
}
|
}
|
||||||
reg += rslt.unwrap(); // concat regions
|
reg += rslt.unwrap(); // concat regions
|
||||||
return sequence<Tail...>::invoke(loc, std::move(reg), first, msg);
|
return sequence<Tail...>::invoke(loc, std::move(reg), first);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,11 +201,10 @@ struct sequence<Head>
|
|||||||
{
|
{
|
||||||
// would be called from sequence<T ...>::invoke only.
|
// would be called from sequence<T ...>::invoke only.
|
||||||
template<typename Cont, typename Iterator>
|
template<typename Cont, typename Iterator>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, region<Cont> reg, Iterator first,
|
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
|
||||||
const bool msg = false)
|
|
||||||
{
|
{
|
||||||
const auto rslt = Head::invoke(loc, msg);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
@@ -240,27 +222,27 @@ template<typename Head, typename ... Tail>
|
|||||||
struct either<Head, Tail...>
|
struct either<Head, Tail...>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
|
|
||||||
const auto rslt = Head::invoke(loc, msg);
|
const auto rslt = Head::invoke(loc);
|
||||||
if(rslt.is_ok()) {return rslt;}
|
if(rslt.is_ok()) {return rslt;}
|
||||||
return either<Tail...>::invoke(loc, msg);
|
return either<Tail...>::invoke(loc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<typename Head>
|
template<typename Head>
|
||||||
struct either<Head>
|
struct either<Head>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
static_assert(std::is_same<char, typename Cont::value_type>::value,
|
||||||
"internal error: container::value_type should be `char`.");
|
"internal error: container::value_type should be `char`.");
|
||||||
return Head::invoke(loc, msg);
|
return Head::invoke(loc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -275,14 +257,14 @@ template<typename T, std::size_t N>
|
|||||||
struct repeat<T, exactly<N>>
|
struct repeat<T, exactly<N>>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region<Cont> retval(loc);
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
for(std::size_t i=0; i<N; ++i)
|
for(std::size_t i=0; i<N; ++i)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc, msg);
|
auto rslt = T::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
@@ -298,15 +280,15 @@ template<typename T, std::size_t N>
|
|||||||
struct repeat<T, at_least<N>>
|
struct repeat<T, at_least<N>>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region<Cont> retval(loc);
|
||||||
|
|
||||||
const auto first = loc.iter();
|
const auto first = loc.iter();
|
||||||
for(std::size_t i=0; i<N; ++i)
|
for(std::size_t i=0; i<N; ++i)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc, msg);
|
auto rslt = T::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
loc.reset(first);
|
loc.reset(first);
|
||||||
@@ -316,7 +298,7 @@ struct repeat<T, at_least<N>>
|
|||||||
}
|
}
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc, msg);
|
auto rslt = T::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
return ok(std::move(retval));
|
return ok(std::move(retval));
|
||||||
@@ -330,13 +312,13 @@ template<typename T>
|
|||||||
struct repeat<T, unlimited>
|
struct repeat<T, unlimited>
|
||||||
{
|
{
|
||||||
template<typename Cont>
|
template<typename Cont>
|
||||||
static result<region<Cont>, std::string>
|
static result<region<Cont>, char>
|
||||||
invoke(location<Cont>& loc, const bool msg = false)
|
invoke(location<Cont>& loc)
|
||||||
{
|
{
|
||||||
region<Cont> retval(loc);
|
region<Cont> retval(loc);
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
auto rslt = T::invoke(loc, msg);
|
auto rslt = T::invoke(loc);
|
||||||
if(rslt.is_err())
|
if(rslt.is_err())
|
||||||
{
|
{
|
||||||
return ok(std::move(retval));
|
return ok(std::move(retval));
|
||||||
|
@@ -376,7 +376,7 @@ parse_ml_basic_string(location<Container>& loc)
|
|||||||
// 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);
|
||||||
|
|
||||||
delim = err("tmp");
|
delim = err('\0');
|
||||||
while(!delim)
|
while(!delim)
|
||||||
{
|
{
|
||||||
using lex_unescaped_seq = repeat<
|
using lex_unescaped_seq = repeat<
|
||||||
@@ -432,7 +432,7 @@ parse_basic_string(location<Container>& loc)
|
|||||||
std::string retval;
|
std::string retval;
|
||||||
retval.reserve(token.unwrap().size());
|
retval.reserve(token.unwrap().size());
|
||||||
|
|
||||||
quot = err("tmp");
|
quot = err('\0');
|
||||||
while(!quot)
|
while(!quot)
|
||||||
{
|
{
|
||||||
using lex_unescaped_seq = repeat<lex_basic_unescaped, unlimited>;
|
using lex_unescaped_seq = repeat<lex_basic_unescaped, unlimited>;
|
||||||
@@ -587,23 +587,17 @@ 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",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), "should be `-`"}}));
|
||||||
}
|
}
|
||||||
inner_loc.advance();
|
inner_loc.advance();
|
||||||
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",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), "should be `-`"}}));
|
||||||
}
|
}
|
||||||
inner_loc.advance();
|
inner_loc.advance();
|
||||||
const auto d = lex_date_mday::invoke(inner_loc);
|
const auto d = lex_date_mday::invoke(inner_loc);
|
||||||
@@ -640,23 +634,17 @@ 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",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), "should be `:`"}}));
|
||||||
}
|
}
|
||||||
inner_loc.advance();
|
inner_loc.advance();
|
||||||
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",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), "should be `:`"}}));
|
||||||
}
|
}
|
||||||
inner_loc.advance();
|
inner_loc.advance();
|
||||||
const auto s = lex_time_second::invoke(inner_loc);
|
const auto s = lex_time_second::invoke(inner_loc);
|
||||||
@@ -724,12 +712,9 @@ 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",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), "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 != ' ')
|
||||||
@@ -769,12 +754,9 @@ 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",
|
||||||
{{std::addressof(inner_loc), msg}}));
|
{{std::addressof(inner_loc), "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))
|
||||||
|
Reference in New Issue
Block a user