#ifndef CHILON_PARSER_SOURCE_CODE_STREAM_HPP
#define CHILON_PARSER_SOURCE_CODE_STREAM_HPP
#include <chilon/parser/stream.hpp>
#include <chilon/parser/choice.hpp>
#include <chilon/parser/until.hpp>
#include <chilon/parser/char.hpp>
#include <chilon/parser/any_char.hpp>
#include <chilon/parser/many.hpp>
#include <chilon/parser/without.hpp>
namespace chilon { namespace parser {
/// The default whitespace parser.
typedef choice< char_<' '>, char_<'\t'>, char_<'\n'> > whitespace;
typedef sequence<
choice<char_<'#', ' '>, char_<'/', '/'> >,
until<char_<'\n'>, any_char>
> default_comment;
typedef choice<whitespace, default_comment> whitespace_and_default_comment;
/// Trim whitespace from the end of a range.
template <class Whitespace>
void trim_end(range& value) {
while (! value.empty() && Whitespace::match_char(value.back()))
--value.end();
}
/**
* @brief This enhances a parser by adding several functions for skipping
* over and to whitespace.
* @tparam Parent parser type to adapt.
* @tparam Whitespace matcher.
* @tparam Comment matcher.
*/
template <class Stream = stream,
class Whitespace = whitespace_and_default_comment>
class source_code_stream : public Stream {
typedef many<Whitespace> skippable_t;
public:
/// Move assignment operator.
template <class Rhs>
source_code_stream& operator=(Rhs&& rhs) {
Stream::operator=(std::move(rhs));
return *this;
}
/**
* @brief Skip whitespace and comments.
* @details This does not check for end of file before skipping, so unless
* the comment or whitespace parsers do then you'd better.
* @post The stream points at the next non-whitespace character.
*/
void skip_whitespace() {
skippable_t::skip(*this);
}
/**
* @brief Like skip_whitespace but remove parser in the list T
* from the whitespace parser when skipping.
* @tparam T should be a meta::list containing parse objects to be
* removed from the whitespace parser.
*/
template <class T>
void skip_whitespace_without() {
many< without<Whitespace, T> >::skip(*this);
}
/**
* @brief Skip whitespace and comments.
* @post The stream points at the next whitespace character.
*/
void skip_to_whitespace() {
while (! this->empty() && ! Whitespace::match(*this)) { this->advance(); }
}
source_code_stream(source_code_stream const& rhs) : Stream(rhs) {}
source_code_stream(source_code_stream&& rhs) : Stream(std::move(rhs)) {}
source_code_stream() {}
};
/// Source code stream with C++ style comments and whitespace.
typedef source_code_stream<
file_stream,
choice<
sequence<
char_<'/', '/'>,
until<char_<'\n'>, any_char>
>,
sequence<
char_<'/', '*'>,
until<char_<'*', '/'>, any_char>
>,
whitespace
>
> cplusplus_stream;
} }
#endif