//! Parsers working with single stream items.
use crate::{
error::{
self, ErrorInfo, ParseError,
ParseResult::{self, *},
ResultExt, StreamError, Tracked,
},
lib::marker::PhantomData,
stream::{uncons, Stream, StreamOnce},
Parser,
};
#[derive(Copy, Clone)]
pub struct Any(PhantomData Input>);
impl Parser for Any
where
Input: Stream,
{
type Output = Input::Token;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
uncons(input)
}
}
/// Parses any token.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// let mut char_parser = any();
/// assert_eq!(char_parser.parse("!").map(|x| x.0), Ok('!'));
/// assert!(char_parser.parse("").is_err());
/// let mut byte_parser = any();
/// assert_eq!(byte_parser.parse(&b"!"[..]).map(|x| x.0), Ok(b'!'));
/// assert!(byte_parser.parse(&b""[..]).is_err());
/// # }
/// ```
pub fn any() -> Any
where
Input: Stream,
{
Any(PhantomData)
}
#[derive(Copy, Clone)]
pub struct Satisfy {
predicate: P,
_marker: PhantomData,
}
fn satisfy_impl(input: &mut Input, mut predicate: P) -> ParseResult
where
Input: Stream,
P: FnMut(Input::Token) -> Option,
{
let position = input.position();
match uncons(input) {
PeekOk(c) | CommitOk(c) => match predicate(c) {
Some(c) => CommitOk(c),
None => PeekErr(Input::Error::empty(position).into()),
},
PeekErr(err) => PeekErr(err),
CommitErr(err) => CommitErr(err),
}
}
impl Parser for Satisfy
where
Input: Stream,
P: FnMut(Input::Token) -> bool,
{
type Output = Input::Token;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
satisfy_impl(input, |c| {
if (self.predicate)(c.clone()) {
Some(c)
} else {
None
}
})
}
}
/// Parses a token and succeeds depending on the result of `predicate`.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// let mut parser = satisfy(|c| c == '!' || c == '?');
/// assert_eq!(parser.parse("!").map(|x| x.0), Ok('!'));
/// assert_eq!(parser.parse("?").map(|x| x.0), Ok('?'));
/// # }
/// ```
pub fn satisfy(predicate: P) -> Satisfy
where
Input: Stream,
P: FnMut(Input::Token) -> bool,
{
Satisfy {
predicate,
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct SatisfyMap {
predicate: P,
_marker: PhantomData,
}
impl Parser for SatisfyMap
where
Input: Stream,
P: FnMut(Input::Token) -> Option,
{
type Output = R;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
satisfy_impl(input, &mut self.predicate)
}
}
/// Parses a token and passes it to `predicate`. If `predicate` returns `Some` the parser succeeds
/// and returns the value inside the `Option`. If `predicate` returns `None` the parser fails
/// without consuming any input.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// #[derive(Debug, PartialEq)]
/// enum YesNo {
/// Yes,
/// No,
/// }
/// let mut parser = satisfy_map(|c| {
/// match c {
/// 'Y' => Some(YesNo::Yes),
/// 'N' => Some(YesNo::No),
/// _ => None,
/// }
/// });
/// assert_eq!(parser.parse("Y").map(|x| x.0), Ok(YesNo::Yes));
/// assert!(parser.parse("A").map(|x| x.0).is_err());
/// # }
/// ```
pub fn satisfy_map(predicate: P) -> SatisfyMap
where
Input: Stream,
P: FnMut(Input::Token) -> Option,
{
SatisfyMap {
predicate,
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct Token
where
Input: Stream,
Input::Token: PartialEq,
{
c: Input::Token,
_marker: PhantomData,
}
impl Parser for Token
where
Input: Stream,
Input::Token: PartialEq + Clone,
{
type Output = Input::Token;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
satisfy_impl(input, |c| if c == self.c { Some(c) } else { None })
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
errors.error.add_expected(error::Token(self.c.clone()));
}
}
/// Parses a character and succeeds if the character is equal to `c`.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// let result = token('!')
/// .parse("!")
/// .map(|x| x.0);
/// assert_eq!(result, Ok('!'));
/// # }
/// ```
pub fn token(c: Input::Token) -> Token
where
Input: Stream,
Input::Token: PartialEq,
{
Token {
c,
_marker: PhantomData,
}
}
#[derive(Clone)]
pub struct Tokens
where
Input: Stream,
{
cmp: C,
expected: E,
tokens: T,
_marker: PhantomData,
}
impl Parser for Tokens
where
C: FnMut(T::Item, Input::Token) -> bool,
E: for<'s> ErrorInfo<'s, Input::Token, Input::Range>,
T: Clone + IntoIterator,
Input: Stream,
{
type Output = T;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
let start = input.position();
let mut committed = false;
for c in self.tokens.clone() {
match crate::stream::uncons(input) {
CommitOk(other) | PeekOk(other) => {
if !(self.cmp)(c, other.clone()) {
return if committed {
let mut errors = ::Error::from_error(
start,
StreamError::unexpected_token(other),
);
errors.add_expected(&self.expected);
CommitErr(errors)
} else {
PeekErr(::Error::empty(start).into())
};
}
committed = true;
}
PeekErr(mut error) => {
error.error.set_position(start);
return if committed {
CommitErr(error.error)
} else {
PeekErr(error)
};
}
CommitErr(mut error) => {
error.set_position(start);
return CommitErr(error);
}
}
}
if committed {
CommitOk(self.tokens.clone())
} else {
PeekOk(self.tokens.clone())
}
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
errors.error.add_expected(&self.expected);
}
}
/// Parses multiple tokens.
///
/// Consumes items from the input and compares them to the values from `tokens` using the
/// comparison function `cmp`. Succeeds if all the items from `tokens` are matched in the input
/// stream and fails otherwise with `expected` used as part of the error.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::error;
/// # fn main() {
/// let result = tokens(|l, r| l.eq_ignore_ascii_case(&r), "abc", "abc".chars())
/// .parse("AbC")
/// .map(|x| x.0.as_str());
/// assert_eq!(result, Ok("abc"));
/// let result = tokens(
/// |&l, r| (if l < r { r - l } else { l - r }) <= 2,
/// error::Range(&b"025"[..]),
/// &b"025"[..]
/// )
/// .parse(&b"123"[..])
/// .map(|x| x.0);
/// assert_eq!(result, Ok(&b"025"[..]));
/// # }
/// ```
pub fn tokens(cmp: C, expected: E, tokens: T) -> Tokens
where
C: FnMut(T::Item, Input::Token) -> bool,
T: Clone + IntoIterator,
Input: Stream,
{
Tokens {
cmp,
expected,
tokens,
_marker: PhantomData,
}
}
#[derive(Clone)]
pub struct TokensCmp
where
Input: Stream,
{
cmp: C,
tokens: T,
_marker: PhantomData,
}
impl Parser for TokensCmp
where
C: FnMut(T::Item, Input::Token) -> bool,
T: Clone + IntoIterator,
Input: Stream,
{
type Output = T;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
let start = input.position();
let mut committed = false;
for c in self.tokens.clone() {
match crate::stream::uncons(input) {
CommitOk(other) | PeekOk(other) => {
if !(self.cmp)(c, other.clone()) {
return if committed {
let errors = ::Error::from_error(
start,
StreamError::unexpected_token(other),
);
CommitErr(errors)
} else {
PeekErr(::Error::empty(start).into())
};
}
committed = true;
}
PeekErr(mut error) => {
error.error.set_position(start);
return if committed {
CommitErr(error.error)
} else {
PeekErr(error)
};
}
CommitErr(mut error) => {
error.set_position(start);
return CommitErr(error);
}
}
}
if committed {
CommitOk(self.tokens.clone())
} else {
PeekOk(self.tokens.clone())
}
}
}
/// Parses multiple tokens.
///
/// Consumes items from the input and compares them to the values from `tokens` using the
/// comparison function `cmp`. Succeeds if all the items from `tokens` are matched in the input
/// stream and fails otherwise.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// # #[allow(deprecated)]
/// # use std::ascii::AsciiExt;
/// let result = tokens_cmp("abc".chars(), |l, r| l.eq_ignore_ascii_case(&r))
/// .parse("AbC")
/// .map(|x| x.0.as_str());
/// assert_eq!(result, Ok("abc"));
/// let result = tokens_cmp(
/// &b"025"[..],
/// |&l, r| (if l < r { r - l } else { l - r }) <= 2,
/// )
/// .parse(&b"123"[..])
/// .map(|x| x.0);
/// assert_eq!(result, Ok(&b"025"[..]));
/// # }
/// ```
pub fn tokens_cmp(tokens: T, cmp: C) -> TokensCmp
where
C: FnMut(T::Item, I::Token) -> bool,
T: Clone + IntoIterator,
I: Stream,
{
TokensCmp {
cmp,
tokens,
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct Position
where
Input: Stream,
{
_marker: PhantomData,
}
impl Parser for Position
where
Input: Stream,
{
type Output = Input::Position;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
PeekOk(input.position())
}
}
/// Parser which just returns the current position in the stream.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::stream::position::{self, SourcePosition};
/// # fn main() {
/// let result = (position(), token('!'), position())
/// .parse(position::Stream::new("!"))
/// .map(|x| x.0);
/// assert_eq!(result, Ok((SourcePosition { line: 1, column: 1 },
/// '!',
/// SourcePosition { line: 1, column: 2 })));
/// # }
/// ```
pub fn position() -> Position
where
Input: Stream,
{
Position {
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct OneOf
where
Input: Stream,
{
tokens: T,
_marker: PhantomData,
}
impl Parser for OneOf
where
T: Clone + IntoIterator- ,
Input: Stream,
Input::Token: PartialEq,
{
type Output = Input::Token;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
satisfy(|c| self.tokens.clone().into_iter().any(|t| t == c)).parse_lazy(input)
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
for expected in self.tokens.clone() {
errors.error.add_expected(error::Token(expected));
}
}
}
/// Extract one token and succeeds if it is part of `tokens`.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// let result = many(one_of("abc".chars()))
/// .parse("abd");
/// assert_eq!(result, Ok((String::from("ab"), "d")));
/// # }
/// ```
pub fn one_of(tokens: T) -> OneOf
where
T: Clone + IntoIterator,
Input: Stream,
Input::Token: PartialEq,
{
OneOf {
tokens,
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct NoneOf
where
Input: Stream,
{
tokens: T,
_marker: PhantomData,
}
impl Parser for NoneOf
where
T: Clone + IntoIterator
- ,
Input: Stream,
Input::Token: PartialEq,
{
type Output = Input::Token;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult {
satisfy(|c| self.tokens.clone().into_iter().all(|t| t != c)).parse_lazy(input)
}
}
/// Extract one token and succeeds if it is not part of `tokens`.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::stream::easy;
/// # use combine::stream::position;
/// # fn main() {
/// let mut parser = many1(none_of(b"abc".iter().cloned()));
/// let result = parser.easy_parse(position::Stream::new(&b"xyb"[..]))
/// .map(|(output, input)| (output, input.input));
/// assert_eq!(result, Ok((b"xy"[..].to_owned(), &b"b"[..])));
///
/// let result = parser.easy_parse(position::Stream::new(&b"ab"[..]));
/// assert_eq!(result, Err(easy::Errors {
/// position: 0,
/// errors: vec![
/// easy::Error::Unexpected(easy::Info::Token(b'a')),
/// ]
/// }));
/// # }
/// ```
pub fn none_of(tokens: T) -> NoneOf
where
T: Clone + IntoIterator,
Input: Stream,
Input::Token: PartialEq,
{
NoneOf {
tokens,
_marker: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct Value(T, PhantomData Input>);
impl Parser for Value
where
Input: Stream,
T: Clone,
{
type Output = T;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, _: &mut Input) -> ParseResult {
PeekOk(self.0.clone())
}
}
/// Always returns the value `v` without consuming any input.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # fn main() {
/// let result = value(42)
/// .parse("hello world")
/// .map(|x| x.0);
/// assert_eq!(result, Ok(42));
/// # }
/// ```
pub fn value(v: T) -> Value
where
Input: Stream,
T: Clone,
{
Value(v, PhantomData)
}
#[derive(Copy, Clone)]
pub struct Produce(F, PhantomData Input>);
impl Parser for Produce
where
Input: Stream,
F: FnMut() -> R,
{
type Output = R;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, _: &mut Input) -> ParseResult {
PeekOk((self.0)())
}
}
/// Always returns the value produced by calling `f`.
///
/// Can be used when `value` is unable to be used for lack of `Clone` implementation on the value.
///
/// ```
/// # use combine::*;
/// #[derive(Debug, PartialEq)]
/// struct NoClone;
/// let result = produce(|| vec![NoClone])
/// .parse("hello world")
/// .map(|x| x.0);
/// assert_eq!(result, Ok(vec![NoClone]));
/// ```
pub fn produce(f: F) -> Produce
where
Input: Stream,
F: FnMut() -> R,
{
Produce(f, PhantomData)
}
#[derive(Copy, Clone)]
pub struct Eof(PhantomData);
impl Parser for Eof
where
Input: Stream,
{
type Output = ();
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<(), Input::Error> {
let before = input.checkpoint();
match input.uncons() {
Err(ref err) if err.is_unexpected_end_of_input() => PeekOk(()),
_ => {
ctry!(input.reset(before).committed());
PeekErr(::Error::empty(input.position()).into())
}
}
}
fn add_error(&mut self, errors: &mut Tracked<::Error>) {
errors.error.add_expected("end of input");
}
}
/// Succeeds only if the stream is at end of input, fails otherwise.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::stream::easy;
/// # use combine::stream::position::{self, SourcePosition};
/// # fn main() {
/// let mut parser = eof();
/// assert_eq!(parser.easy_parse(position::Stream::new("")), Ok(((), position::Stream::new(""))));
/// assert_eq!(parser.easy_parse(position::Stream::new("x")), Err(easy::Errors {
/// position: SourcePosition::default(),
/// errors: vec![
/// easy::Error::Unexpected('x'.into()),
/// easy::Error::Expected("end of input".into())
/// ]
/// }));
/// # }
/// ```
pub fn eof() -> Eof
where
Input: Stream,
{
Eof(PhantomData)
}