#ifndef CHILON_PARSER_CHAR_HPP
#define CHILON_PARSER_CHAR_HPP
#include <chilon/parser/detail/char.hpp>
#include <chilon/parser/skip.hpp>
namespace chilon { namespace parser {
template <class T>
struct char_base {
template <class Stream>
inline static bool match(Stream const& stream) {
return T::match_char(stream.front());
}
template <class Stream>
inline static bool skip(Stream& stream) {
if (match(stream)) {
stream.advance();
return true;
}
else return false;
}
};
/**
* @brief Matches multiple characters consecutively.
* @tparam c A parameter pack of the characters to match.
*/
template <char... c>
struct char_;
/**
* @brief Matches a single character.
* @tparam c The character to match.
*/
template <char c>
struct char_<c> : char_base<char_<c>> {
template <class Char>
inline static bool match_char(Char const ch) {
return ch == c;
}
};
template <char... T>
struct char_from;
template <>
struct char_from<> {
template <class Char>
inline static bool match_char(Char const ch) {
return false;
}
};
template <char H, char... T>
struct char_from<H, T...> : char_base<char_from<H, T...>> {
template <class Char>
inline static bool match_char(Char const ch) {
return ch == H || char_from<T...>::match_char(ch);
}
};
template <char... T>
struct parse<char_from<T...>> : detail::parse_char<char_from<T...>> {};
template <char... T>
struct not_char_from;
template <>
struct not_char_from<> {
template <class Char>
inline static bool match_char(Char const ch) {
return true;
}
};
template <char H, char... T>
struct not_char_from<H, T...> : char_base<not_char_from<H, T...>> {
template <class Char>
inline static bool match_char(Char const ch) {
return ch != H && not_char_from<T...>::match_char(ch);
}
};
template <char... T>
struct parse<not_char_from<T...>> : detail::parse_char<not_char_from<T...>> {};
/**
* @brief Matches multiple characters in a row.
* @tparam cs Parameter pack of the characters to match.
*/
template <char... cs>
struct char_ {
template <int idx, char... tail>
struct match_tail;
template <int idx, char head>
struct match_tail<idx, head> {
template <class Stream>
inline static bool match(Stream const& stream) {
return head == stream[idx];
}
};
template <int idx, char head, char... tail>
struct match_tail<idx, head, tail...> {
template <class Stream>
inline static bool match(Stream const& stream) {
return head == stream[idx] && match_tail<idx + 1, tail...>::match(stream);
}
};
template <class Stream>
inline static bool match(Stream const& stream) {
return stream.size() > sizeof...(cs) && match_tail<0, cs...>::match(stream);
}
template <class Stream>
inline static bool skip(Stream& stream) {
if (match(stream)) {
stream.advance(sizeof...(cs));
return true;
}
else return false;
}
};
template <char C>
struct parse<char_<C>> : skip_<char_<C>, detail::parse_char<char_<C>>> {};
template <char... C>
struct parse<char_<C...>> : skip_<char_<C...>, detail::parse_range<char_<C...>>> {};
// TODO: reimplement this in terms of not_char_from
struct non_whitespace : char_base<non_whitespace> {
template <class Char>
inline static bool match_char(Char const ch) {
return ch != ' ' && ch != '\n' && ch != '\t';
}
};
template <>
struct parse<non_whitespace> : detail::parse_char<non_whitespace> {};
} }
#endif