246 lines
6.2 KiB
Rust
246 lines
6.2 KiB
Rust
//! Parsers which cause errors or modifies the returned error on parse failure.
|
|
|
|
use crate::{
|
|
error::{
|
|
ErrorInfo, ParseError,
|
|
ParseResult::{self, *},
|
|
StreamError, Tracked,
|
|
},
|
|
lib::marker::PhantomData,
|
|
parser::ParseMode,
|
|
Parser, Stream, StreamOnce,
|
|
};
|
|
|
|
#[derive(Clone)]
|
|
pub struct Unexpected<I, T, E>(E, PhantomData<fn(I) -> (I, T)>)
|
|
where
|
|
I: Stream;
|
|
impl<Input, T, E> Parser<Input> for Unexpected<Input, T, E>
|
|
where
|
|
Input: Stream,
|
|
E: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
type Output = T;
|
|
type PartialState = ();
|
|
#[inline]
|
|
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<T, <Input as StreamOnce>::Error> {
|
|
PeekErr(<Input as StreamOnce>::Error::empty(input.position()).into())
|
|
}
|
|
fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
|
|
errors.error.add(StreamError::unexpected(&self.0));
|
|
}
|
|
}
|
|
/// Always fails with `message` as an unexpected error.
|
|
/// Never consumes any input.
|
|
///
|
|
/// Has `()` the output type
|
|
///
|
|
/// ```
|
|
/// # extern crate combine;
|
|
/// # use combine::*;
|
|
/// # use combine::error::StreamError;
|
|
/// # fn main() {
|
|
/// let result = unexpected("token")
|
|
/// .easy_parse("a");
|
|
/// assert!(result.is_err());
|
|
/// assert!(
|
|
/// result.err()
|
|
/// .unwrap()
|
|
/// .errors
|
|
/// .iter()
|
|
/// .any(|m| *m == StreamError::unexpected("token"))
|
|
/// );
|
|
/// # }
|
|
/// ```
|
|
pub fn unexpected<Input, S>(message: S) -> Unexpected<Input, (), S>
|
|
where
|
|
Input: Stream,
|
|
S: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
unexpected_any(message)
|
|
}
|
|
|
|
/// Always fails with `message` as an unexpected error.
|
|
/// Never consumes any input.
|
|
///
|
|
/// May have anything as the output type but must be used such that the output type can inferred.
|
|
/// The `unexpected` parser can be used if the output type does not matter
|
|
///
|
|
/// ```
|
|
/// # extern crate combine;
|
|
/// # use combine::*;
|
|
/// # use combine::parser::error::unexpected_any;
|
|
/// # use combine::error::StreamError;
|
|
/// # fn main() {
|
|
/// let result = token('b').or(unexpected_any("token"))
|
|
/// .easy_parse("a");
|
|
/// assert!(result.is_err());
|
|
/// assert!(
|
|
/// result.err()
|
|
/// .unwrap()
|
|
/// .errors
|
|
/// .iter()
|
|
/// .any(|m| *m == StreamError::unexpected("token"))
|
|
/// );
|
|
/// # }
|
|
/// ```
|
|
pub fn unexpected_any<Input, S, T>(message: S) -> Unexpected<Input, T, S>
|
|
where
|
|
Input: Stream,
|
|
S: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
Unexpected(message, PhantomData)
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Message<P, S>(P, S);
|
|
impl<Input, P, S> Parser<Input> for Message<P, S>
|
|
where
|
|
Input: Stream,
|
|
P: Parser<Input>,
|
|
S: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
type Output = P::Output;
|
|
type PartialState = P::PartialState;
|
|
|
|
parse_mode!(Input);
|
|
#[inline]
|
|
fn parse_mode_impl<M>(
|
|
&mut self,
|
|
mode: M,
|
|
input: &mut Input,
|
|
state: &mut Self::PartialState,
|
|
) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
|
|
where
|
|
M: ParseMode,
|
|
{
|
|
match self.0.parse_mode(mode, input, state) {
|
|
CommitOk(x) => CommitOk(x),
|
|
PeekOk(x) => PeekOk(x),
|
|
|
|
// The message should always be added even if some input was committed before failing
|
|
CommitErr(mut err) => {
|
|
err.add_message(&self.1);
|
|
CommitErr(err)
|
|
}
|
|
|
|
// The message will be added in `add_error`
|
|
PeekErr(err) => PeekErr(err),
|
|
}
|
|
}
|
|
|
|
fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
|
|
self.0.add_error(errors);
|
|
errors.error.add_message(&self.1);
|
|
}
|
|
|
|
forward_parser!(Input, parser_count add_committed_expected_error, 0);
|
|
}
|
|
|
|
/// Equivalent to [`p1.message(msg)`].
|
|
///
|
|
/// [`p1.message(msg)`]: ../trait.Parser.html#method.message
|
|
pub fn message<Input, P, S>(p: P, msg: S) -> Message<P, S>
|
|
where
|
|
P: Parser<Input>,
|
|
Input: Stream,
|
|
S: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
Message(p, msg)
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Expected<P, S>(P, S);
|
|
impl<Input, P, S> Parser<Input> for Expected<P, S>
|
|
where
|
|
P: Parser<Input>,
|
|
Input: Stream,
|
|
S: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
type Output = P::Output;
|
|
type PartialState = P::PartialState;
|
|
|
|
parse_mode!(Input);
|
|
#[inline]
|
|
fn parse_mode_impl<M>(
|
|
&mut self,
|
|
mode: M,
|
|
input: &mut Input,
|
|
state: &mut Self::PartialState,
|
|
) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
|
|
where
|
|
M: ParseMode,
|
|
{
|
|
self.0.parse_mode(mode, input, state)
|
|
}
|
|
|
|
fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
|
|
ParseError::set_expected(errors, StreamError::expected(&self.1), |errors| {
|
|
self.0.add_error(errors);
|
|
})
|
|
}
|
|
|
|
forward_parser!(Input, parser_count add_committed_expected_error, 0);
|
|
}
|
|
|
|
/// Equivalent to [`p.expected(info)`].
|
|
///
|
|
/// [`p.expected(info)`]: ../trait.Parser.html#method.expected
|
|
pub fn expected<Input, P, S>(p: P, info: S) -> Expected<P, S>
|
|
where
|
|
P: Parser<Input>,
|
|
Input: Stream,
|
|
S: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
|
|
{
|
|
Expected(p, info)
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Silent<P>(P);
|
|
impl<Input, P> Parser<Input> for Silent<P>
|
|
where
|
|
P: Parser<Input>,
|
|
Input: Stream,
|
|
{
|
|
type Output = P::Output;
|
|
type PartialState = P::PartialState;
|
|
|
|
parse_mode!(Input);
|
|
#[inline]
|
|
fn parse_mode_impl<M>(
|
|
&mut self,
|
|
mode: M,
|
|
input: &mut Input,
|
|
state: &mut Self::PartialState,
|
|
) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
|
|
where
|
|
M: ParseMode,
|
|
{
|
|
self.0.parse_mode(mode, input, state).map_err(|mut err| {
|
|
err.clear_expected();
|
|
err
|
|
})
|
|
}
|
|
|
|
fn add_error(&mut self, _errors: &mut Tracked<<Input as StreamOnce>::Error>) {}
|
|
|
|
fn add_committed_expected_error(
|
|
&mut self,
|
|
_errors: &mut Tracked<<Input as StreamOnce>::Error>,
|
|
) {
|
|
}
|
|
|
|
forward_parser!(Input, parser_count, 0);
|
|
}
|
|
|
|
/// Equivalent to [`p.silent()`].
|
|
///
|
|
/// [`p.silent()`]: ../trait.Parser.html#method.silent
|
|
pub fn silent<Input, P>(p: P) -> Silent<P>
|
|
where
|
|
P: Parser<Input>,
|
|
Input: Stream,
|
|
{
|
|
Silent(p)
|
|
}
|