//! Combinators which take one or more parsers and attempts to parse successfully with at least one //! of them. use crate::{ error::{ ParseError, ParseResult::{self, *}, ResultExt, StreamError, Tracked, }, parser::ParseMode, ErrorOffset, Parser, Stream, StreamOnce, }; /// Takes a number of parsers and tries to apply them each in order. /// Fails if all the parsers fails or if an applied parser fails after it has committed to its /// parse. /// /// ``` /// # #[macro_use] /// # extern crate combine; /// # use combine::*; /// # use combine::parser::char::{digit, letter, string}; /// # use combine::stream::easy::Error; /// # fn main() { /// let mut parser = choice!( /// many1(digit()), /// string("let").map(|s| s.to_string()), /// many1(letter())); /// assert_eq!(parser.parse("let"), Ok(("let".to_string(), ""))); /// assert_eq!(parser.parse("123abc"), Ok(("123".to_string(), "abc"))); /// assert!(parser.parse(":123").is_err()); /// # } /// ``` #[macro_export] macro_rules! choice { ($first : expr) => { $first }; ($first : expr, $($rest : expr),+) => { $first.or(choice!($($rest),+)) } } #[macro_export] #[doc(hidden)] macro_rules! parse_mode_choice { (Input) => { fn parse_partial( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> { self.parse_mode_choice($crate::parser::PartialMode::default(), input, state) } fn parse_first( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult { self.parse_mode_choice($crate::parser::FirstMode, input, state) } }; } /// `ChoiceParser` represents a parser which may parse one of several different choices depending /// on the input. /// /// This is an internal trait used to overload the `choice` function. pub trait ChoiceParser { type Output; type PartialState: Default; fn parse_first( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error>; fn parse_partial( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error>; fn parse_mode_choice( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, Self: Sized; fn add_error_choice(&mut self, error: &mut Tracked<::Error>); } impl<'a, Input, P> ChoiceParser for &'a mut P where Input: Stream, P: ?Sized + ChoiceParser, { type Output = P::Output; type PartialState = P::PartialState; parse_mode_choice!(Input); #[inline] fn parse_mode_choice( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { if mode.is_first() { (**self).parse_first(input, state) } else { (**self).parse_partial(input, state) } } fn add_error_choice(&mut self, error: &mut Tracked<::Error>) { (**self).add_error_choice(error) } } macro_rules! merge { ($head: ident) => { $head.error }; ($head: ident $($tail: ident)+) => { $head.error.merge(merge!($($tail)+)) }; } macro_rules! do_choice { ( $input: ident $before_position: ident $before: ident $partial_state: ident $state: ident ( ) $($parser: ident $error: ident)+ ) => { { let mut error = Tracked::from(merge!($($error)+)); // If offset != 1 then the nested parser is a sequence of parsers where 1 or // more parsers returned `PeekOk` before the parser finally failed with // `PeekErr`. Since we lose the offsets of the nested parsers when we merge // the errors we must first extract the errors before we do the merge. // If the offset == 0 on the other hand (which should be the common case) then // we can delay the addition of the error since we know for certain that only // the first parser in the sequence were tried $( if $error.offset != ErrorOffset(1) { error.offset = $error.offset; $parser.add_error(&mut error); error.offset = ErrorOffset(0); } )+ PeekErr(error) } }; ( $input: ident $before_position: ident $before: ident $partial_state: ident $state: ident ( $head: ident $($tail: ident)* ) $($all: ident)* ) => { { let parser = $head; let mut state = $head::PartialState::default(); match parser.parse_mode(crate::parser::FirstMode, $input, &mut state) { CommitOk(x) => CommitOk(x), PeekOk(x) => PeekOk(x), CommitErr(err) => { // If we get `CommitErr` but the input is the same this is a partial parse we // cannot commit to so leave the state as `Peek` to retry all the parsers // on the next call to `parse_partial` if $input.position() != $before_position { *$state = self::$partial_state::$head(state); } CommitErr(err) } PeekErr($head) => { ctry!($input.reset($before.clone()).committed()); do_choice!( $input $before_position $before $partial_state $state ( $($tail)* ) $($all)* parser $head ) } } } } } macro_rules! tuple_choice_parser { ($head: ident) => { tuple_choice_parser_inner!($head; $head); }; ($head: ident $($id: ident)+) => { tuple_choice_parser_inner!($head; $head $($id)+); tuple_choice_parser!($($id)+); }; } macro_rules! tuple_choice_parser_inner { ($partial_state: ident; $($id: ident)+) => { #[doc(hidden)] pub enum $partial_state<$($id),+> { Peek, $( $id($id), )+ } impl<$($id),+> Default for self::$partial_state<$($id),+> { fn default() -> Self { self::$partial_state::Peek } } #[allow(non_snake_case)] impl ChoiceParser for ($($id,)+) where Input: Stream, $($id: Parser< Input, Output = Output>),+ { type Output = Output; type PartialState = self::$partial_state<$($id::PartialState),+>; parse_mode_choice!(Input); #[inline] fn parse_mode_choice( &mut self, mode: Mode, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where Mode: ParseMode, { let ($(ref mut $id,)+) = *self; let empty = match *state { self::$partial_state::Peek => true, _ => false, }; if mode.is_first() || empty { let before_position = input.position(); let before = input.checkpoint(); do_choice!(input before_position before $partial_state state ( $($id)+ ) ) } else { match *state { self::$partial_state::Peek => unreachable!(), $( self::$partial_state::$id(_) => { let result = match *state { self::$partial_state::$id(ref mut state) => { $id.parse_mode(mode, input, state) } _ => unreachable!() }; if result.is_ok() { *state = self::$partial_state::Peek; } result } )+ } } } fn add_error_choice( &mut self, error: &mut Tracked<::Error> ) { if error.offset != ErrorOffset(0) { let ($(ref mut $id,)+) = *self; // Reset the offset to 1 on every add so that we always (and only) takes the // error of the first parser. If we don't do this the first parser will consume // the offset to the detriment for all the other parsers. $( error.offset = ErrorOffset(1); $id.add_error(error); )+ } } } } } tuple_choice_parser!(A B C D E F G H I J K L M N O P Q R S T U V X Y Z); macro_rules! array_choice_parser { ($($t: tt)+) => { $( impl ChoiceParser for [P; $t] where Input: Stream, P: Parser, { type Output = P::Output; type PartialState = <[P] as ChoiceParser>::PartialState; parse_mode_choice!(Input); #[inline] fn parse_mode_choice( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { if mode.is_first() { self[..].parse_first(input, state) } else { self[..].parse_partial(input, state) } } fn add_error_choice( &mut self, error: &mut Tracked<::Error> ) { self[..].add_error_choice(error) } } )+ }; } #[rustfmt::skip] array_choice_parser!( 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ); #[derive(Copy, Clone)] pub struct Choice

(P); impl Parser for Choice

where Input: Stream, P: ChoiceParser, { type Output = P::Output; type PartialState = P::PartialState; parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { self.0.parse_mode_choice(mode, input, state) } fn add_error(&mut self, error: &mut Tracked<::Error>) { let before = error.offset.0; self.0.add_error_choice(error); error.offset.0 = before.saturating_sub(1); } } fn slice_parse_mode( self_: &mut [P], mode: M, input: &mut Input, state: &mut (usize, P::PartialState), ) -> ParseResult::Error> where P: Parser, Input: Stream, M: ParseMode, { let mut prev_err = None; let mut last_parser_having_non_1_offset = 0; let before = input.checkpoint(); let (ref mut index_state, ref mut child_state) = *state; if !mode.is_first() && *index_state != 0 { return self_[*index_state - 1] .parse_partial(input, child_state) .map(|x| { *index_state = 0; x }); } for i in 0..self_.len() { ctry!(input.reset(before.clone()).committed()); match self_[i].parse_mode(mode, input, child_state) { committed_err @ CommitErr(_) => { *index_state = i + 1; return committed_err; } PeekErr(err) => { prev_err = match prev_err { None => Some(err), Some(mut prev_err) => { if prev_err.offset != ErrorOffset(1) { // First add the errors of all the preceding parsers which did not // have a sequence of parsers returning `PeekOk` before failing // with `PeekErr`. let offset = prev_err.offset; for p in &mut self_[last_parser_having_non_1_offset..(i - 1)] { prev_err.offset = ErrorOffset(1); p.add_error(&mut prev_err); } // Then add the errors if the current parser prev_err.offset = offset; self_[i - 1].add_error(&mut prev_err); last_parser_having_non_1_offset = i; } Some(Tracked { error: prev_err.error.merge(err.error), offset: err.offset, }) } }; } ok @ CommitOk(_) | ok @ PeekOk(_) => { *index_state = 0; return ok; } } } PeekErr(match prev_err { None => Input::Error::from_error( input.position(), StreamError::message_static_message("parser choice is empty"), ) .into(), Some(mut prev_err) => { if prev_err.offset != ErrorOffset(1) { let offset = prev_err.offset; let len = self_.len(); for p in &mut self_[last_parser_having_non_1_offset..(len - 1)] { prev_err.offset = ErrorOffset(1); p.add_error(&mut prev_err); } prev_err.offset = offset; self_.last_mut().unwrap().add_error(&mut prev_err); prev_err.offset = ErrorOffset(0); } prev_err } }) } impl ChoiceParser for [P] where Input: Stream, P: Parser, { type Output = O; type PartialState = (usize, P::PartialState); #[inline] fn parse_partial( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> { slice_parse_mode(self, crate::parser::PartialMode::default(), input, state) } #[inline] fn parse_first( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> { slice_parse_mode(self, crate::parser::FirstMode, input, state) } #[inline] fn parse_mode_choice( &mut self, _mode: M, _input: &mut Input, _state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { unreachable!() } fn add_error_choice(&mut self, error: &mut Tracked<::Error>) { if error.offset != ErrorOffset(0) { for p in self { error.offset = ErrorOffset(1); p.add_error(error); } } } } /// Takes a tuple, a slice or an array of parsers and tries to apply them each in order. /// Fails if all the parsers fails or if an applied parser consumes input before failing. /// /// ``` /// # extern crate combine; /// # use combine::*; /// # use combine::parser::char::{digit, string}; /// # fn main() { /// // `choice` is overloaded on tuples so that different types of parsers can be used /// // (each parser must still have the same input and output types) /// let mut parser = choice(( /// string("Apple").map(|s| s.to_string()), /// many1(digit()), /// string("Orange").map(|s| s.to_string()), /// )); /// assert_eq!(parser.parse("1234"), Ok(("1234".to_string(), ""))); /// assert_eq!(parser.parse("Orangexx"), Ok(("Orange".to_string(), "xx"))); /// assert!(parser.parse("Appl").is_err()); /// assert!(parser.parse("Pear").is_err()); /// /// // If arrays or slices are used then all parsers must have the same type /// // (`string` in this case) /// let mut parser2 = choice([string("one"), string("two"), string("three")]); /// // Fails as the parser for "two" consumes the first 't' before failing /// assert!(parser2.parse("three").is_err()); /// /// // Use 'attempt' to make failing parsers always act as if they have not committed any input /// let mut parser3 = choice([attempt(string("one")), attempt(string("two")), attempt(string("three"))]); /// assert_eq!(parser3.parse("three"), Ok(("three", ""))); /// # } /// ``` pub fn choice(ps: P) -> Choice

where Input: Stream, P: ChoiceParser, { Choice(ps) } #[derive(Copy, Clone)] pub struct Or(Choice<(P1, P2)>); impl Parser for Or where Input: Stream, P1: Parser, P2: Parser, { type Output = O; type PartialState = as Parser>::PartialState; parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { self.0.parse_mode(mode, input, state) } #[inline] fn add_error(&mut self, errors: &mut Tracked<::Error>) { if errors.offset != ErrorOffset(0) { self.0.add_error(errors); } } } /// Equivalent to [`p1.or(p2)`]. /// /// If you are looking to chain 3 or more parsers using `or` you may consider using the /// [`choice!`] macro instead, which can be clearer and may result in a faster parser. /// /// ``` /// # extern crate combine; /// # use combine::*; /// # use combine::parser::choice::or; /// # use combine::parser::char::{digit, string}; /// # fn main() { /// let mut parser = or( /// string("let"), /// or(digit().map(|_| "digit"), string("led")), /// ); /// assert_eq!(parser.parse("let"), Ok(("let", ""))); /// assert_eq!(parser.parse("1"), Ok(("digit", ""))); /// assert!(parser.parse("led").is_err()); /// /// let mut parser2 = or(string("two"), string("three")); /// // Fails as the parser for "two" consumes the first 't' before failing /// assert!(parser2.parse("three").is_err()); /// /// // Use 'attempt' to make failing parsers always act as if they have not committed any input /// let mut parser3 = or(attempt(string("two")), attempt(string("three"))); /// assert_eq!(parser3.parse("three"), Ok(("three", ""))); /// # } /// ``` /// /// [`choice!`]: ../../macro.choice.html /// [`p1.or(p2)`]: ../trait.Parser.html#method.or pub fn or(p1: P1, p2: P2) -> Or where Input: Stream, P1: Parser, P2: Parser, { Or(choice((p1, p2))) } #[derive(Copy, Clone)] pub struct Optional

(P); impl Parser for Optional

where Input: Stream, P: Parser, { type Output = Option; type PartialState = P::PartialState; parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { let before = input.checkpoint(); match self.0.parse_mode(mode, input, state) { PeekOk(x) => PeekOk(Some(x)), CommitOk(x) => CommitOk(Some(x)), CommitErr(err) => CommitErr(err), PeekErr(_) => { ctry!(input.reset(before).committed()); PeekOk(None) } } } forward_parser!(Input, add_error parser_count, 0); } /// Parses `parser` and outputs `Some(value)` if it succeeds, `None` if it fails without /// consuming any input. Fails if `parser` fails after having committed some input. /// /// ``` /// # extern crate combine; /// # use combine::*; /// # use combine::parser::char::string; /// # fn main() { /// let mut parser = optional(string("hello")); /// assert_eq!(parser.parse("hello"), Ok((Some("hello"), ""))); /// assert_eq!(parser.parse("world"), Ok((None, "world"))); /// assert!(parser.parse("heya").is_err()); /// # } /// ``` pub fn optional(parser: P) -> Optional

where Input: Stream, P: Parser, { Optional(parser) } #[macro_export] #[doc(hidden)] macro_rules! parse_mode_dispatch { () => { fn parse_partial( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> { self.parse_mode_dispatch($crate::parser::PartialMode::default(), input, state) } fn parse_first( &mut self, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> { self.parse_mode_dispatch($crate::parser::FirstMode, input, state) } }; } #[macro_export] #[doc(hidden)] macro_rules! dispatch_parser_impl { ($parser_name: ident [$first_ident: ident $($id: ident)*] [$($collected_idents: ident)*] $expr: expr, $($rest: expr,)*) => { $crate::dispatch_parser_impl!{ $parser_name [ $($id)* ] [$($collected_idents)* $first_ident] $($rest,)*} }; ($parser_name: ident [$($id: ident)*] [$($collected_idents: ident)*]) => { $crate::dispatch_parser_impl!{ $parser_name; $($collected_idents)* } }; ($parser_name: ident; $($id: ident)*) => { pub enum $parser_name<$($id),*> { $( $id($id), )* } #[allow(non_snake_case)] impl $crate::Parser for $parser_name<$($id),*> where $( $id: $crate::Parser, )* Input: $crate::Stream, { type Output = Output; type PartialState = Option<$parser_name<$($id::PartialState),*>>; $crate::parse_mode!(Input); fn parse_mode( &mut self, mode: Mode, input: &mut Input, state: &mut Self::PartialState, ) -> $crate::error::ParseResult::Error> where Mode: $crate::parser::ParseMode, { match self { $( $parser_name::$id($id) => { let state = match state { Some($parser_name::$id(s)) => s, _ => { *state = Some($parser_name::$id(Default::default())); match state { Some($parser_name::$id(s)) => s, _ => unreachable!(), } } }; $id.parse_mode(mode, input, state) } )* } } fn add_error(&mut self, error: &mut $crate::error::Tracked<::Error>) { match self { $( $parser_name::$id($id) => $id.add_error(error), )* } } } } } #[macro_export] #[doc(hidden)] macro_rules! dispatch_inner { ($expr_ident: ident [$first_ident: ident $($id: ident)*] [$($collected: tt)*] $($pat: pat)|+ $(if $pred:expr)? => $expr: expr, $($rest_alt: tt)*) => { $crate::dispatch_inner!{ $expr_ident [ $($id)* ] [$($collected)* $first_ident $($pat)|+ $(if $pred)? => $expr,] $($rest_alt)*} }; ($expr_ident: ident [$($id: ident)*] [$($collected: tt)*]) => { $crate::dispatch_inner!{ $expr_ident $($collected)* } }; ($expr_ident: ident [$($ident_tt: tt)*]) => { unreachable!() }; ($expr_ident: ident $( $ident: ident $($pat: pat)|+ $(if $pred:expr)? => $expr: expr,)+ ) => { match $expr_ident { $( $($pat)|+ $(if $pred)? => Dispatch::$ident(check_parser($expr)), )+ } } } /// `dispatch!` allows a parser to be constructed depending on earlier input, without forcing each /// branch to have the same type of parser /// /// ``` /// use combine::{dispatch, any, token, satisfy, EasyParser, Parser}; /// /// let mut parser = any().then(|e| { /// dispatch!(e; /// 'a' => token('a'), /// 'b' => satisfy(|b| b == 'b'), /// t if t == 'c' => any(), /// _ => token('d') /// ) /// }); /// assert_eq!(parser.easy_parse("aa"), Ok(('a', ""))); /// assert_eq!(parser.easy_parse("cc"), Ok(('c', ""))); /// assert_eq!(parser.easy_parse("cd"), Ok(('d', ""))); /// assert!(parser.easy_parse("ab").is_err()); /// ``` #[macro_export] macro_rules! dispatch { ($match_expr: expr; $( $($pat: pat)|+ $(if $pred:expr)? => $expr: expr ),+ $(,)? ) => { { $crate::dispatch_parser_impl!{ Dispatch [A B C D E F G H I J K L M N O P Q R S T U V X Y Z] [] $($expr,)+ } fn check_parser(p: P) -> P where P: $crate::Parser, Input: $crate::Stream { p } let e = $match_expr; let parser = $crate::dispatch_inner!(e [A B C D E F G H I J K L M N O P Q R S T U V X Y Z] [] $( $($pat)|+ $(if $pred)? => $expr, )* ); parser } } } #[cfg(all(feature = "std", test))] mod tests { use crate::parser::{token::any, EasyParser}; use super::*; #[test] fn choice_single_parser() { assert!(choice((any(),),).easy_parse("a").is_ok()); } }