//! 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) }