Skip to content

Commit 154c054

Browse files
committed
Add loop_parser and loop_gen
1 parent e505ab8 commit 154c054

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

src/parser/sequence.rs

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,3 +891,204 @@ 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, S, P, G> Parser<Input> for Loop<F, S>
899+
where
900+
Input: Stream,
901+
F: FnMut(&mut S) -> P,
902+
S: Clone,
903+
P: Parser<Input, Output = G>,
904+
G: FnOnce(&mut S)
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+
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+
LoopGen(next_func, || init_state.clone()).parse_mode_impl(mode, input, state)
922+
}
923+
}
924+
925+
// Takes a function `func` and initial `state`. Function is applied to current
926+
// state and generates a parser outputting function to update the state. This
927+
// is repeated until the generated parser fails.
928+
//
929+
/// ```
930+
/// # extern crate combine;
931+
/// # use std::collections::HashMap;
932+
/// # use combine::{Parser, Stream, many1, token, value, unexpected_any, optional, choice};
933+
/// # use combine::parser::char::digit;
934+
/// # use combine::parser::sequence::loop_parser;
935+
/// # fn main() {
936+
/// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count
937+
/// #[derive(PartialEq, Eq, Clone, Hash)]
938+
/// enum Token { A, B, C }
939+
/// fn token_parser<Input>(last_token: &Option<Token>) -> impl Parser<Input, Output = Token>
940+
/// where
941+
/// Input: Stream<Token = char>
942+
/// {
943+
/// let mut choices = vec![];
944+
/// if *last_token != Some(Token::A) {
945+
/// choices.push(token('a').map(|_| Token::A).left());
946+
/// }
947+
/// if *last_token != Some(Token::B) {
948+
/// choices.push(token('b').map(|_| Token::B).left().right());
949+
/// }
950+
/// if *last_token != Some(Token::C) {
951+
/// choices.push(token('c').map(|_| Token::C).right().right());
952+
/// }
953+
/// choice(choices)
954+
/// }
955+
/// let result = loop_parser((HashMap::<Token, usize>::new(), None), |(_, last_token)| {
956+
/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::<Token, usize>, Option<Token>)| {
957+
/// *acc.entry(current_token.clone()).or_insert(0) += 1;
958+
/// *last_token = Some(current_token);
959+
/// })
960+
/// }).map(|x| x.0).parse("ababacbcbcaa");
961+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4)));
962+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4)));
963+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3)));
964+
/// assert_eq!(result.as_ref().map(|x| x.1), Ok("a"));
965+
/// # }
966+
/// ```
967+
pub fn loop_parser<Input, F, P, G, S>(state: S, func: F) -> Loop<F, S>
968+
where
969+
Input: Stream,
970+
F: FnMut(&mut S) -> P,
971+
P: Parser<Input, Output = G>,
972+
G: FnOnce(&mut S),
973+
S: Clone
974+
{
975+
Loop(func, state)
976+
}
977+
978+
#[derive(Copy, Clone)]
979+
pub struct LoopGen<F, G>(F, G);
980+
981+
impl<Input, F, G, S, P, H> Parser<Input> for LoopGen<F, G>
982+
where
983+
Input: Stream,
984+
F: FnMut(&mut S) -> P,
985+
G: FnMut() -> S,
986+
P: Parser<Input, Output = H>,
987+
H: FnOnce(&mut S)
988+
{
989+
type Output = S;
990+
type PartialState = (Option<S>, Option<P>, bool, P::PartialState);
991+
992+
parse_mode!(Input);
993+
#[inline]
994+
fn parse_mode_impl<M>(
995+
&mut self,
996+
mut mode: M,
997+
input: &mut Input,
998+
state: &mut Self::PartialState,
999+
) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
1000+
where
1001+
M: ParseMode,
1002+
{
1003+
let Self(ref mut next_func, ref mut state_gen) = *self;
1004+
let (ref mut state, ref mut parser, ref mut committed, ref mut partial_state) = *state;
1005+
if mode.is_first() {
1006+
debug_assert!(state.is_none());
1007+
debug_assert!(parser.is_none());
1008+
debug_assert!(!*committed);
1009+
*state = Some(state_gen());
1010+
*parser = Some(next_func(state.as_mut().unwrap()));
1011+
}
1012+
let parser = parser.as_mut().unwrap();
1013+
loop {
1014+
let before = input.checkpoint();
1015+
let result = parser.parse_mode_impl(mode, input, partial_state);
1016+
let mutator = match result {
1017+
CommitOk(next_mutator) => {
1018+
*committed = true;
1019+
next_mutator
1020+
},
1021+
PeekOk(next_mutator) => next_mutator,
1022+
CommitErr(e) => return CommitErr(e),
1023+
PeekErr(_) => {
1024+
match input.reset(before) {
1025+
Ok(_) => if *committed {
1026+
return CommitOk(state.take().unwrap())
1027+
} else {
1028+
return PeekOk(state.take().unwrap())
1029+
},
1030+
Err(err) => return CommitErr(err)
1031+
};
1032+
}
1033+
};
1034+
let state = state.as_mut().unwrap();
1035+
mutator(state);
1036+
*parser = next_func(state);
1037+
*partial_state = Default::default();
1038+
mode.set_first();
1039+
}
1040+
}
1041+
}
1042+
1043+
// Takes a function `func` and initial `state`. Function is applied to current
1044+
// state and generates a parser outputting function to update the state. This
1045+
// is repeated until the generated parser fails.
1046+
//
1047+
/// ```
1048+
/// # extern crate combine;
1049+
/// # use std::collections::HashMap;
1050+
/// # use combine::{Parser, Stream, many1, token, value, unexpected_any, optional, choice};
1051+
/// # use combine::parser::char::digit;
1052+
/// # use combine::parser::sequence::loop_gen;
1053+
/// # fn main() {
1054+
/// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count
1055+
/// #[derive(PartialEq, Eq, Clone, Hash)]
1056+
/// enum Token { A, B, C }
1057+
/// fn token_parser<Input>(last_token: &Option<Token>) -> impl Parser<Input, Output = Token>
1058+
/// where
1059+
/// Input: Stream<Token = char>
1060+
/// {
1061+
/// let mut choices = vec![];
1062+
/// if *last_token != Some(Token::A) {
1063+
/// choices.push(token('a').map(|_| Token::A).left());
1064+
/// }
1065+
/// if *last_token != Some(Token::B) {
1066+
/// choices.push(token('b').map(|_| Token::B).left().right());
1067+
/// }
1068+
/// if *last_token != Some(Token::C) {
1069+
/// choices.push(token('c').map(|_| Token::C).right().right());
1070+
/// }
1071+
/// choice(choices)
1072+
/// }
1073+
/// let result = loop_gen(|| (HashMap::<Token, usize>::new(), None), |(_, last_token)| {
1074+
/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::<Token, usize>, Option<Token>)| {
1075+
/// *acc.entry(current_token.clone()).or_insert(0) += 1;
1076+
/// *last_token = Some(current_token);
1077+
/// })
1078+
/// }).map(|x| x.0).parse("ababacbcbcaa");
1079+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4)));
1080+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4)));
1081+
/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3)));
1082+
/// assert_eq!(result.as_ref().map(|x| x.1), Ok("a"));
1083+
/// # }
1084+
/// ```
1085+
pub fn loop_gen<Input, F, G, S, P, H>(state_gen: G, func: F) -> LoopGen<F, G>
1086+
where
1087+
Input: Stream,
1088+
F: FnMut(&mut S) -> P,
1089+
G: FnMut() -> S,
1090+
P: Parser<Input, Output = H>,
1091+
H: FnOnce(&mut S)
1092+
{
1093+
LoopGen(func, state_gen)
1094+
}

0 commit comments

Comments
 (0)