feat: use detail::none_t instead of char

Although the error value from combinators currently does not have any
information, it can have an information because it is a char value. It
is better to use no-information-type explicitly to make it clear that
it does not have any information. So I added none_t in toml::detai and
use it in combinators and parsers as an error value from combinators.
This commit is contained in:
ToruNiina 2019-05-31 17:07:52 +09:00
parent 81abb6c9d7
commit 717f5929c2
3 changed files with 46 additions and 25 deletions

View File

@ -56,19 +56,19 @@ struct character
static constexpr char target = C;
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err('\0');}
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
const char c = *(loc.iter());
if(c != target)
{
return err(c);
return none();
}
loc.advance(); // update location
@ -89,19 +89,19 @@ struct in_range
static constexpr char lower = Low;
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err('\0');}
if(loc.iter() == loc.end()) {return none();}
const auto first = loc.iter();
const char c = *(loc.iter());
if(c < lower || upper < c)
{
return err(c);
return none();
}
loc.advance();
@ -117,20 +117,20 @@ template<typename Combinator>
struct exclude
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
"internal error: container::value_type should be `char`.");
if(loc.iter() == loc.end()) {return err('\0');}
if(loc.iter() == loc.end()) {return none();}
auto first = loc.iter();
auto rslt = Combinator::invoke(loc);
if(rslt.is_ok())
{
loc.reset(first);
return err(*first);
return none();
}
loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
return ok(region<Cont>(loc, first, loc.iter()));
@ -142,7 +142,7 @@ template<typename Combinator>
struct maybe
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
@ -164,7 +164,7 @@ template<typename Head, typename ... Tail>
struct sequence<Head, Tail...>
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
@ -175,21 +175,21 @@ struct sequence<Head, Tail...>
if(rslt.is_err())
{
loc.reset(first);
return err(rslt.unwrap_err());
return none();
}
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
}
// called from the above function only, recursively.
template<typename Cont, typename Iterator>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.reset(first);
return err(rslt.unwrap_err());
return none();
}
reg += rslt.unwrap(); // concat regions
return sequence<Tail...>::invoke(loc, std::move(reg), first);
@ -201,14 +201,14 @@ struct sequence<Head>
{
// would be called from sequence<T ...>::invoke only.
template<typename Cont, typename Iterator>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc, region<Cont> reg, Iterator first)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.reset(first);
return err(rslt.unwrap_err());
return none();
}
reg += rslt.unwrap(); // concat regions
return ok(reg);
@ -222,7 +222,7 @@ template<typename Head, typename ... Tail>
struct either<Head, Tail...>
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
@ -237,7 +237,7 @@ template<typename Head>
struct either<Head>
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
static_assert(std::is_same<char, typename Cont::value_type>::value,
@ -257,7 +257,7 @@ template<typename T, std::size_t N>
struct repeat<T, exactly<N>>
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region<Cont> retval(loc);
@ -268,7 +268,7 @@ struct repeat<T, exactly<N>>
if(rslt.is_err())
{
loc.reset(first);
return err(rslt.unwrap_err());
return none();
}
retval += rslt.unwrap();
}
@ -280,7 +280,7 @@ template<typename T, std::size_t N>
struct repeat<T, at_least<N>>
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region<Cont> retval(loc);
@ -292,7 +292,7 @@ struct repeat<T, at_least<N>>
if(rslt.is_err())
{
loc.reset(first);
return err(rslt.unwrap_err());
return none();
}
retval += rslt.unwrap();
}
@ -312,7 +312,7 @@ template<typename T>
struct repeat<T, unlimited>
{
template<typename Cont>
static result<region<Cont>, char>
static result<region<Cont>, none_t>
invoke(location<Cont>& loc)
{
region<Cont> retval(loc);

View File

@ -376,7 +376,7 @@ parse_ml_basic_string(location<Container>& loc)
// immediate newline is ignored (if exists)
/* discard return value */ lex_newline::invoke(inner_loc);
delim = err('\0');
delim = none();
while(!delim)
{
using lex_unescaped_seq = repeat<
@ -432,7 +432,7 @@ parse_basic_string(location<Container>& loc)
std::string retval;
retval.reserve(token.unwrap().size());
quot = err('\0');
quot = none();
while(!quot)
{
using lex_unescaped_seq = repeat<lex_basic_unescaped, unlimited>;

View File

@ -692,5 +692,26 @@ void swap(result<T, E>& lhs, result<T, E>& rhs)
// return lhs.is_ok() ? lhs : rhs;
// }
// ----------------------------------------------------------------------------
// re-use result<T, E> as a optional<T> with none_t
namespace detail
{
struct none_t {};
inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
template<typename charT, typename traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
{
os << "none";
return os;
}
inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
} // detail
} // toml11
#endif// TOML11_RESULT_H