Skip to content

Commit 0af270c

Browse files
committed
Add loop_parser
1 parent e505ab8 commit 0af270c

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

src/parser/sequence.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,3 +891,125 @@ where
891891
{
892892
ThenRef(p, f)
893893
}
894+
895+
#[derive(Copy, Clone)]
896+
pub struct Loop<F, S>(F, S);
897+
898+
impl<Input, F, P, G, S> Parser<Input> for Loop<F, S>
899+
where
900+
Input: Stream,
901+
F: FnMut(&mut S) -> P,
902+
P: Parser<Input, Output = G>,
903+
G: FnOnce(&mut S),
904+
S: Clone
905+
{
906+
type Output = S;
907+
type PartialState = (Option<S>, Option<P>, bool, P::PartialState);
908+
909+
parse_mode!(Input);
910+
#[inline]
911+
fn parse_mode_impl<M>(
912+
&mut self,
913+
mut mode: M,
914+
input: &mut Input,
915+
state: &mut Self::PartialState,
916+
) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
917+
where
918+
M: ParseMode,
919+
{
920+
let Self(ref mut next_func, ref init_state) = *self;
921+
let (ref mut state, ref mut parser, ref mut committed, ref mut partial_state) = *state;
922+
if mode.is_first() {
923+
debug_assert!(state.is_none());
924+
debug_assert!(parser.is_none());
925+
debug_assert!(!*committed);
926+
*state = Some(init_state.clone());
927+
*parser = Some(next_func(state.as_mut().unwrap()));
928+
}
929+
let parser = parser.as_mut().unwrap();
930+
loop {
931+
let before = input.checkpoint();
932+
let result = parser.parse_mode_impl(mode, input, partial_state);
933+
let mutator = match result {
934+
CommitOk(next_mutator) => {
935+
*committed = true;
936+
next_mutator
937+
},
938+
PeekOk(next_mutator) => next_mutator,
939+
CommitErr(e) => return CommitErr(e),
940+
PeekErr(_) => {
941+
match input.reset(before) {
942+
Ok(_) => if *committed {
943+
return CommitOk(state.take().unwrap())
944+
} else {
945+
return PeekOk(state.take().unwrap())
946+
},
947+
Err(err) => return CommitErr(err)
948+
};
949+
}
950+
};
951+
let state = state.as_mut().unwrap();
952+
mutator(state);
953+
*parser = next_func(state);
954+
*partial_state = Default::default();
955+
mode.set_first();
956+
}
957+
}
958+
}
959+
960+
961+
// If `init` is not `None` it parses using it first. Than subsequently
962+
// applies `func` to result until `None` is returned. The result is
963+
// the last state.
964+
//
965+
// Otherwise, if `init` is `None`, it returns the `state` without
966+
// consuming any input.
967+
//
968+
/// ```
969+
/// # extern crate combine;
970+
/// # use std::collections::HashMap;
971+
/// # use combine::{Parser, Stream, many1, token, value, unexpected_any, optional, choice};
972+
/// # use combine::parser::char::digit;
973+
/// # use combine::parser::sequence::loop_parser;
974+
/// # fn main() {
975+
/// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count
976+
/// #[derive(PartialEq, Eq, Clone, Hash)]
977+
/// enum Token { A, B, C }
978+
/// fn token_parser<Input>(last_token: &Option<Token>) -> impl Parser<Input, Output = Token>
979+
/// where
980+
/// Input: Stream<Token = char>
981+
/// {
982+
/// let mut choices = vec![];
983+
/// if *last_token != Some(Token::A) {
984+
/// choices.push(token('a').map(|_| Token::A).left());
985+
/// }
986+
/// if *last_token != Some(Token::B) {
987+
/// choices.push(token('b').map(|_| Token::B).left().right());
988+
/// }
989+
/// if *last_token != Some(Token::C) {
990+
/// choices.push(token('c').map(|_| Token::C).right().right());
991+
/// }
992+
/// choice(choices)
993+
/// }
994+
/// let result = loop_parser((HashMap::<Token, usize>::new(), None), |(_, last_token)| {
995+
/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::<Token, usize>, Option<Token>)| {
996+
/// *acc.entry(current_token.clone()).or_insert(0) += 1;
997+
/// *last_token = Some(current_token);
998+
/// })
999+
/// }).map(|x| x.0).parse("ababacbcbcaa");
1000+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4)));
1001+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4)));
1002+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3)));
1003+
/// assert_eq!(result.as_ref().map(|x| x.1), Ok("a"));
1004+
/// # }
1005+
/// ```
1006+
pub fn loop_parser<Input, F, P, G, S>(state: S, func: F) -> Loop<F, S>
1007+
where
1008+
Input: Stream,
1009+
F: FnMut(&mut S) -> P,
1010+
P: Parser<Input, Output = G>,
1011+
G: FnOnce(&mut S),
1012+
S: Clone
1013+
{
1014+
Loop(func, state)
1015+
}

0 commit comments

Comments
 (0)