//! Combinators which take multiple parsers and applies them one after another. use crate::{ error::{ ParseError, ParseResult::{self, *}, StreamError, Tracked, }, lib::marker::PhantomData, parser::{ combinator::{ignore, Ignore, Map}, ParseMode, }, ErrorOffset, Parser, Stream, StreamOnce, }; macro_rules! count { () => { 0 }; ($f: ident) => { 1 }; ($f: ident, $($rest: ident),+) => { 1 + count!($($rest),*) }; } #[doc(hidden)] pub struct SequenceState { pub value: Option, pub state: U, } impl Default for SequenceState { fn default() -> Self { SequenceState { value: None, state: U::default(), } } } impl SequenceState where U: Default, { unsafe fn unwrap_value(&mut self) -> T { match self.value.take() { Some(t) => t, None => core::hint::unreachable_unchecked(), } } } macro_rules! last_ident { ($id: ident) => { $id }; ($id: ident, $($rest: ident),+) => { last_ident!($($rest),+) }; } fn add_sequence_error( i: &mut usize, first_empty_parser: usize, inner_offset: ErrorOffset, err: &mut Tracked, parser: &mut impl Parser, ) -> bool where Input: Stream, { if *i + 1 == first_empty_parser { Parser::add_committed_expected_error(parser, err); } if *i >= first_empty_parser { if err.offset <= ErrorOffset(1) { // We reached the last parser we need to add errors to (and the // parser that actually returned the error), use the returned // offset for that parser. err.offset = inner_offset; } Parser::add_error(parser, err); if err.offset <= ErrorOffset(1) { return false; } } err.offset = ErrorOffset(err.offset.0.saturating_sub(Parser::parser_count(parser).0)); *i += 1; true } macro_rules! tuple_parser { ($partial_state: ident; $h: ident $(, $id: ident)*) => { #[allow(non_snake_case)] #[derive(Default)] pub struct $partial_state < $h $(, $id )* > { pub $h: $h, $( pub $id: $id, )* #[allow(dead_code)] offset: u8, _marker: PhantomData <( $h, $( $id),* )>, } #[allow(non_snake_case)] impl<$h $(, $id)*> $partial_state<$h $(, $id)*> { #[allow(dead_code)] fn add_errors( input: &mut Input, mut err: Tracked, first_empty_parser: usize, offset: u8, $h: &mut $h $(, $id : &mut $id )* ) -> ParseResult<($h::Output, $($id::Output),*), ::Error> where Input: Stream, $h: Parser, $($id: Parser),* { let inner_offset = err.offset; err.offset = ErrorOffset(offset); if first_empty_parser != 0 { if let Ok(t) = input.uncons() { err.error.add(StreamError::unexpected_token(t)); } #[allow(unused_assignments)] let mut i = 0; loop { if !add_sequence_error(&mut i, first_empty_parser, inner_offset, &mut err, $h) { break; } $( if !add_sequence_error(&mut i, first_empty_parser, inner_offset, &mut err, $id) { break; } )* break; } CommitErr(err.error) } else { PeekErr(err) } } } #[allow(non_snake_case)] impl Parser for ($h, $($id),*) where Input: Stream, $h: Parser, $($id: Parser),* { type Output = ($h::Output, $($id::Output),*); type PartialState = $partial_state< SequenceState<$h::Output, $h::PartialState> $(, SequenceState<$id::Output, $id::PartialState>)* >; parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mut mode: MODE, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where MODE: ParseMode, { let (ref mut $h, $(ref mut $id),*) = *self; let mut first_empty_parser = 0; #[allow(unused_mut)] let mut current_parser = 0; #[allow(unused_macros)] macro_rules! add_errors { ($err: ident, $offset: expr) => { $partial_state::add_errors( input, $err, first_empty_parser, $offset, $h, $($id),* ) } } if mode.is_first() || state.$h.value.is_none() { let temp = match $h.parse_mode(mode, input, &mut state.$h.state) { CommitOk(x) => { first_empty_parser = current_parser + 1; x } PeekErr(err) => return PeekErr(err), CommitErr(err) => return CommitErr(err), PeekOk(x) => { x } }; state.offset = $h.parser_count().0.saturating_add(1); // SAFETY: must be set to avoid UB below when unwrapping state.$h.value = Some(temp); // Once we have successfully parsed the partial input we may resume parsing in // "first mode" mode.set_first(); } $( if mode.is_first() || state.$id.value.is_none() { current_parser += 1; let before = input.checkpoint(); let temp = match $id.parse_mode(mode, input, &mut state.$id.state) { CommitOk(x) => { first_empty_parser = current_parser + 1; x } PeekErr(err) => { if let Err(err) = input.reset(before) { return if first_empty_parser != 0 { CommitErr(err.into()) } else { PeekErr(err.into()) }; } return add_errors!(err, state.offset) } CommitErr(err) => return CommitErr(err), PeekOk(x) => { x } }; state.offset = state.offset.saturating_add($id.parser_count().0); // SAFETY: must be set to avoid UB below when unwrapping state.$id.value = Some(temp); // Once we have successfully parsed the partial input we may resume parsing in // "first mode" mode.set_first(); } )* // SAFETY: requires both $h and $id to be set, see previous SAFETY comments let value = unsafe { (state.$h.unwrap_value(), $(state.$id.unwrap_value()),*) }; if first_empty_parser != 0 { CommitOk(value) } else { PeekOk(value) } } #[inline] fn parser_count(&self) -> ErrorOffset { let (ref $h, $(ref $id),*) = *self; ErrorOffset($h.parser_count().0 $( + $id.parser_count().0)*) } #[inline] fn add_error(&mut self, errors: &mut Tracked<::Error>) { let (ref mut $h, $(ref mut $id),*) = *self; let prev = errors.offset; $h.add_error(errors); if errors.offset <= ErrorOffset(1) { errors.offset = ErrorOffset( errors.offset.0.saturating_sub(1) ); return; } if errors.offset == prev { errors.offset = ErrorOffset(errors.offset.0.saturating_sub($h.parser_count().0)); } #[allow(dead_code)] const LAST: usize = count!($($id),*); #[allow(unused_mut, unused_variables)] let mut i = 0; $( i += 1; let prev = errors.offset; $id.add_error(errors); if errors.offset <= ErrorOffset(1) { errors.offset = ErrorOffset( errors.offset.0.saturating_sub(1) ); return; } if i != LAST && errors.offset == prev { errors.offset = ErrorOffset( errors.offset.0.saturating_sub($id.parser_count().0) ); } )* } fn add_committed_expected_error(&mut self, errors: &mut Tracked<::Error>) { #[allow(unused_variables)] let (ref mut $h, $(ref mut $id),*) = *self; last_ident!($h $(, $id)*).add_committed_expected_error(errors) } } } } tuple_parser!(PartialState1; A); tuple_parser!(PartialState2; A, B); tuple_parser!(PartialState3; A, B, C); tuple_parser!(PartialState4; A, B, C, D); tuple_parser!(PartialState5; A, B, C, D, E); tuple_parser!(PartialState6; A, B, C, D, E, F); tuple_parser!(PartialState7; A, B, C, D, E, F, G); tuple_parser!(PartialState8; A, B, C, D, E, F, G, H); tuple_parser!(PartialState9; A, B, C, D, E, F, G, H, I); tuple_parser!(PartialState10; A, B, C, D, E, F, G, H, I, J); tuple_parser!(PartialState11; A, B, C, D, E, F, G, H, I, J, K); tuple_parser!(PartialState12; A, B, C, D, E, F, G, H, I, J, K, L); tuple_parser!(PartialState13; A, B, C, D, E, F, G, H, I, J, K, L, M); tuple_parser!(PartialState14; A, B, C, D, E, F, G, H, I, J, K, L, M, N); tuple_parser!(PartialState15; A, B, C, D, E, F, G, H, I, J, K, L, M, N, P); tuple_parser!(PartialState16; A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q); tuple_parser!(PartialState17; A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R); tuple_parser!(PartialState18; A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R, S); tuple_parser!(PartialState19; A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R, S, T); tuple_parser!(PartialState20; A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R, S, T, U); #[macro_export] #[doc(hidden)] macro_rules! seq_parser_expr { (; $($tt: tt)*) => { ( $($tt)* ) }; ( (_ : $first_parser: expr, $($remaining: tt)+ ); $($tt: tt)*) => { $crate::seq_parser_expr!( ( $($remaining)+ ) ; $($tt)* $first_parser, ) }; ( ($first_field: ident : $first_parser: expr, $($remaining: tt)+ ); $($tt: tt)*) => { $crate::seq_parser_expr!( ( $($remaining)+ ) ; $($tt)* $first_parser, ) }; ( (_ : $first_parser: expr ); $($tt: tt)*) => { ( $($tt)* $first_parser, ) }; ( ($first_field: ident : $first_parser: expr, ); $($tt: tt)*) => { $crate::seq_parser_expr!(; $($tt)* $first_parser,) }; ( (_ : $first_parser: expr, ); $($tt: tt)*) => { ( $($tt)* $first_parser, ) }; ( ($first_field: ident : $first_parser: expr ); $($tt: tt)*) => { $crate::seq_parser_expr!(; $($tt)* $first_parser,) }; } #[macro_export] #[doc(hidden)] macro_rules! seq_parser_pattern { (; $($tt: tt)*) => { ( $($tt)* ) }; ( (_ : $first_parser: expr, $($remaining: tt)+ ); $($tt: tt)*) => { $crate::seq_parser_pattern!( ( $($remaining)+ ) ; $($tt)* _, ) }; ( ($first_field: ident : $first_parser: expr, $($remaining: tt)+ ); $($tt: tt)*) => { $crate::seq_parser_pattern!( ( $($remaining)+ ) ; $($tt)* $first_field, ) }; ( ( _ : $first_parser: expr ); $($tt: tt)*) => { $crate::seq_parser_pattern!(; $($tt)* _, ) }; ( ($first_field: ident : $first_parser: expr ); $($tt: tt)*) => { $crate::seq_parser_pattern!(; $($tt)* $first_field,) }; ( ( _ : $first_parser: expr, ); $($tt: tt)*) => { $crate::seq_parser_pattern!(; $($tt)* _, ) }; ( ($first_field: ident : $first_parser: expr, ); $($tt: tt)*) => { $crate::seq_parser_pattern!(; $($tt)* $first_field,) }; } #[macro_export] #[doc(hidden)] macro_rules! seq_parser_impl { (; $name: ident $($tt: tt)*) => { $name { $($tt)* } }; ( (_ : $first_parser: expr, $($remaining: tt)+ ); $name: ident $($tt: tt)*) => { $crate::seq_parser_impl!( ( $($remaining)+ ) ; $name $($tt)* ) }; ( ($first_field: ident : $first_parser: expr, $($remaining: tt)+ ); $name: ident $($tt: tt)*) => { $crate::seq_parser_impl!( ( $($remaining)+ ) ; $name $($tt)* $first_field: $first_field, ) }; ( ( _ : $first_parser: expr ); $name: ident $($tt: tt)*) => { $crate::seq_parser_impl!( ; $name $($tt)* ) }; ( ($first_field: ident : $first_parser: expr ); $name: ident $($tt: tt)*) => { $crate::seq_parser_impl!(; $name $($tt)* $first_field: $first_field,) }; ( ( _ : $first_parser: expr, ); $name: ident $($tt: tt)*) => { $crate::seq_parser_impl!(; $name $($tt)*) }; ( ($first_field: ident : $first_parser: expr, ); $name: ident $($tt: tt)*) => { $crate::seq_parser_impl!(; $name $($tt)* $first_field: $first_field,) }; } #[macro_export] #[doc(hidden)] macro_rules! seq_tuple_extract { (; ; $name: ident ; $($arg: expr),* $(,)? ) => { $name( $($arg,)* ) }; ( (_ : $first_parser: expr, $($remaining: tt)+ ); ( $first_arg: expr, $($arg: expr),* ) ; $($tt: tt)*) => { $crate::seq_tuple_extract!( ( $($remaining)+ ); ( $($arg),* ) ; $($tt)* ) }; ( ($first_parser: expr, $($remaining: tt)+ ); ( $first_arg: expr, $($arg: expr),* ) ; $($tt: tt)*) => { $crate::seq_tuple_extract!( ( $($remaining)+ ) ; ( $($arg),* ) ; $($tt)* $first_arg, ) }; ( (_ : $first_parser: expr $(,)? ); ( $first_arg: expr, $($arg: expr),* ) ; $($tt: tt)*) => { $crate::seq_tuple_extract!(; ; $($tt)*) }; ( ($first_parser: expr $(,)? ); ( $first_arg: expr, $($arg: expr),* ) ; $($tt: tt)*) => { $crate::seq_tuple_extract!(; ; $($tt)* $first_arg) }; } #[macro_export] #[doc(hidden)] macro_rules! seq_tuple_parser_impl { (; $($tt: tt)*) => { ($($tt)*) }; ( (_ : $first_parser: expr, $($remaining: tt)+ ); $($tt: tt)*) => { $crate::seq_tuple_parser_impl!( ( $($remaining)+ ) ; $($tt)* $first_parser, ) }; ( ($first_parser: expr, $($remaining: tt)+ ); $($tt: tt)*) => { $crate::seq_tuple_parser_impl!( ( $($remaining)+ ) ; $($tt)* $first_parser, ) }; ( (_ : $first_parser: expr $(,)? ); $($tt: tt)*) => { $crate::seq_tuple_parser_impl!(; $($tt)* $first_parser, ) }; ( ($first_parser: expr $(,)? ); $($tt: tt)*) => { $crate::seq_tuple_parser_impl!(; $($tt)* $first_parser, ) }; } /// Sequences multiple parsers and builds a struct out of them. /// /// ``` /// use combine::{Parser, between, from_str, many, struct_parser, token}; /// use combine::parser::range::take_while1; /// use combine::parser::byte::{letter, spaces}; /// /// #[derive(Debug, PartialEq)] /// struct Point(u32, u32); /// /// #[derive(Debug, PartialEq)] /// struct Field { /// name: Vec, /// value: Vec, /// point: Point, /// } /// fn main() { /// let num = || from_str(take_while1(|b: u8| b >= b'0' && b <= b'9')); /// let spaced = |b| between(spaces(), spaces(), token(b)); /// let mut parser = struct_parser!{ /// Field { /// name: many(letter()), /// // `_` fields are ignored when building the struct /// _: spaced(b':'), /// value: many(letter()), /// _: spaced(b':'), /// point: struct_parser!(Point(num(), _: spaced(b','), num())), /// } /// }; /// assert_eq!( /// parser.parse(&b"test: data: 123 , 4"[..]), /// Ok(( /// Field { /// name: b"test"[..].to_owned(), /// value: b"data"[..].to_owned(), /// point: Point(123, 4), /// }, /// &b""[..] /// )), /// ); /// } /// ``` #[macro_export] macro_rules! struct_parser { ($name: ident { $($tt: tt)* }) => { $crate::seq_parser_expr!( ( $($tt)* ); ) .map(|$crate::seq_parser_pattern!( ( $($tt)* ); )| $crate::seq_parser_impl!(( $($tt)* ); $name ) ) }; ($name: ident ( $($arg: tt)* )) => { $crate::seq_tuple_parser_impl!( ( $($arg)* ) ; ) .map(|t| $crate::seq_tuple_extract!( ( $($arg)* ); (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14); $name ; ) ) } } #[derive(Copy, Clone)] pub struct With((Ignore, P2)); impl Parser for With where Input: Stream, P1: Parser, P2: Parser, { type Output = P2::Output; type PartialState = <(Ignore, P2) as Parser>::PartialState; #[inline] fn parse_lazy( &mut self, input: &mut Input, ) -> ParseResult::Error> { self.0.parse_lazy(input).map(|(_, b)| b) } 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).map(|(_, b)| b) } forward_parser!(Input, add_error add_committed_expected_error parser_count, 0); } /// Equivalent to [`p1.with(p2)`]. /// /// [`p1.with(p2)`]: ../trait.Parser.html#method.with pub fn with(p1: P1, p2: P2) -> With where Input: Stream, P1: Parser, P2: Parser, { With((ignore(p1), p2)) } #[derive(Copy, Clone)] pub struct Skip((P1, Ignore)); impl Parser for Skip where Input: Stream, P1: Parser, P2: Parser, { type Output = P1::Output; type PartialState = <(P1, Ignore) 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).map(|(a, _)| a) } forward_parser!(Input, add_error add_committed_expected_error parser_count, 0); } pub fn skip(p1: P1, p2: P2) -> Skip where Input: Stream, P1: Parser, P2: Parser, { Skip((p1, ignore(p2))) } parser! { #[derive(Copy, Clone)] pub struct Between; type PartialState = P::Output> as Parser>::PartialState; /// Parses `open` followed by `parser` followed by `close`. /// Returns the value of `parser`. /// /// ``` /// # extern crate combine; /// # use combine::*; /// # use combine::parser::char::string; /// # fn main() { /// let result = between(token('['), token(']'), string("rust")) /// .parse("[rust]") /// .map(|x| x.0); /// assert_eq!(result, Ok("rust")); /// # } /// ``` pub fn between[Input, L, R, P](open: L, close: R, parser: P)(Input) -> P::Output where [ Input: Stream, L: Parser< Input>, R: Parser< Input>, P: Parser< Input>, ] { fn middle((_, x, _): (T, U, V)) -> U { x } (open, parser, close).map(middle) } } #[derive(Copy, Clone)] pub struct Then(P, F); impl Parser for Then where Input: Stream, F: FnMut(P::Output) -> N, P: Parser, N: Parser, { type Output = N::Output; type PartialState = (P::PartialState, Option<(bool, N)>, N::PartialState); parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mut mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { let (ref mut p_state, ref mut n_parser_cache, ref mut n_state) = *state; if mode.is_first() || n_parser_cache.is_none() { debug_assert!(n_parser_cache.is_none()); let (value, committed) = match self.0.parse_mode(mode, input, p_state) { PeekOk(value) => (value, false), CommitOk(value) => (value, true), PeekErr(err) => return PeekErr(err), CommitErr(err) => return CommitErr(err), }; *n_parser_cache = Some((committed, (self.1)(value))); mode.set_first(); } let result = n_parser_cache .as_mut() .unwrap() .1 .parse_committed_mode(mode, input, n_state); match result { PeekOk(x) => { let (committed, _) = *n_parser_cache.as_ref().unwrap(); *n_parser_cache = None; if committed { CommitOk(x) } else { PeekOk(x) } } CommitOk(x) => { *n_parser_cache = None; CommitOk(x) } PeekErr(x) => { let (committed, _) = *n_parser_cache.as_ref().unwrap(); *n_parser_cache = None; if committed { CommitErr(x.error) } else { PeekErr(x) } } CommitErr(x) => CommitErr(x), } } fn add_error(&mut self, errors: &mut Tracked<::Error>) { self.0.add_error(errors); } } /// Equivalent to [`p.then(f)`]. /// /// [`p.then(f)`]: ../trait.Parser.html#method.then pub fn then(p: P, f: F) -> Then where Input: Stream, F: FnMut(P::Output) -> N, P: Parser, N: Parser, { Then(p, f) } #[derive(Copy, Clone)] pub struct ThenPartial(P, F); impl Parser for ThenPartial where Input: Stream, F: FnMut(&mut P::Output) -> N, P: Parser, N: Parser, { type Output = N::Output; type PartialState = (P::PartialState, Option<(bool, P::Output)>, N::PartialState); parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mut mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { let (ref mut p_state, ref mut n_parser_cache, ref mut n_state) = *state; if mode.is_first() || n_parser_cache.is_none() { debug_assert!(n_parser_cache.is_none()); match self.0.parse_mode(mode, input, p_state) { PeekOk(value) => { *n_parser_cache = Some((false, value)); } CommitOk(value) => { *n_parser_cache = Some((true, value)); } PeekErr(err) => return PeekErr(err), CommitErr(err) => return CommitErr(err), } mode.set_first(); } let result = (self.1)(&mut n_parser_cache.as_mut().unwrap().1) .parse_committed_mode(mode, input, n_state); match result { PeekOk(x) => { let (committed, _) = n_parser_cache.take().unwrap(); if committed { CommitOk(x) } else { PeekOk(x) } } CommitOk(x) => { *n_parser_cache = None; CommitOk(x) } PeekErr(x) => { let (committed, _) = n_parser_cache.take().unwrap(); if committed { CommitErr(x.error) } else { PeekErr(x) } } CommitErr(x) => CommitErr(x), } } fn add_error(&mut self, errors: &mut Tracked<::Error>) { self.0.add_error(errors); } } /// Equivalent to [`p.then_partial(f)`]. /// /// [`p.then_partial(f)`]: ../trait.Parser.html#method.then_partial pub fn then_partial(p: P, f: F) -> ThenPartial where Input: Stream, F: FnMut(&mut P::Output) -> N, P: Parser, N: Parser, { ThenPartial(p, f) } #[cfg(all(feature = "std", test))] mod tests { use crate::parser::{token::any, EasyParser}; #[test] fn sequence_single_parser() { assert!((any(),).easy_parse("a").is_ok()); } } #[derive(Copy, Clone)] pub struct ThenRef(P, F); impl Parser for ThenRef where Input: Stream, F: FnMut(&P::Output) -> N, P: Parser, N: Parser, { type Output = (P::Output, N::Output); type PartialState = ( P::PartialState, Option<(bool, P::Output, N)>, N::PartialState, ); parse_mode!(Input); #[inline] fn parse_mode_impl( &mut self, mut mode: M, input: &mut Input, state: &mut Self::PartialState, ) -> ParseResult::Error> where M: ParseMode, { let (ref mut p_state, ref mut n_parser_cache, ref mut n_state) = *state; if mode.is_first() || n_parser_cache.is_none() { debug_assert!(n_parser_cache.is_none()); let (value, committed) = match self.0.parse_mode(mode, input, p_state) { PeekOk(value) => (value, false), CommitOk(value) => (value, true), PeekErr(err) => return PeekErr(err), CommitErr(err) => return CommitErr(err), }; let parser = (self.1)(&value); *n_parser_cache = Some((committed, value, parser)); mode.set_first(); } let result = n_parser_cache .as_mut() .unwrap() .2 .parse_committed_mode(mode, input, n_state); match result { PeekOk(x) => { let (committed, in_value, _) = n_parser_cache.take().unwrap(); if committed { CommitOk((in_value, x)) } else { PeekOk((in_value, x)) } } CommitOk(x) => { let (_, in_value, _) = n_parser_cache.take().unwrap(); *n_parser_cache = None; CommitOk((in_value, x)) } PeekErr(x) => { let (committed, _, _) = n_parser_cache.take().unwrap(); *n_parser_cache = None; if committed { CommitErr(x.error) } else { PeekErr(x) } } CommitErr(x) => CommitErr(x), } } fn add_error(&mut self, errors: &mut Tracked<::Error>) { self.0.add_error(errors); } } /// Equivalent to [`p.then_ref(f)`]. /// /// [`p.then_ref(f)`]: ../trait.Parser.html#method.then pub fn then_ref(p: P, f: F) -> ThenRef where Input: Stream, F: FnMut(&P::Output) -> N, P: Parser, N: Parser, { ThenRef(p, f) }