From e505ab890922f4c5e0321cd3d330ef3c55b87b09 Mon Sep 17 00:00:00 2001 From: Maciej Piechotka Date: Sun, 27 Jun 2021 23:44:27 -0700 Subject: [PATCH 1/4] Add ChoiceParser for Vec

to allow passing vectors to choice --- src/parser/choice.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/parser/choice.rs b/src/parser/choice.rs index 8efdb0c3..f7aecc4b 100644 --- a/src/parser/choice.rs +++ b/src/parser/choice.rs @@ -350,6 +350,41 @@ array_choice_parser!( 30 31 32 ); +#[cfg(feature = "std")] +impl ChoiceParser for Vec

+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) + } +} + #[derive(Copy, Clone)] pub struct Choice

(P); From 154c0545f235de2f95547ee5583f4b0cd98ccb66 Mon Sep 17 00:00:00 2001 From: Maciej Piechotka Date: Sun, 27 Jun 2021 22:56:39 -0700 Subject: [PATCH 2/4] Add loop_parser and loop_gen --- src/parser/sequence.rs | 201 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/src/parser/sequence.rs b/src/parser/sequence.rs index b296966a..5a6b6d4e 100644 --- a/src/parser/sequence.rs +++ b/src/parser/sequence.rs @@ -891,3 +891,204 @@ where { ThenRef(p, f) } + +#[derive(Copy, Clone)] +pub struct Loop(F, S); + +impl Parser for Loop +where + Input: Stream, + F: FnMut(&mut S) -> P, + S: Clone, + P: Parser, + G: FnOnce(&mut S) +{ + type Output = S; + type PartialState = (Option, Option

, bool, 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 Self(ref mut next_func, ref init_state) = *self; + LoopGen(next_func, || init_state.clone()).parse_mode_impl(mode, input, state) + } +} + +// Takes a function `func` and initial `state`. Function is applied to current +// state and generates a parser outputting function to update the state. This +// is repeated until the generated parser fails. +// +/// ``` +/// # extern crate combine; +/// # use std::collections::HashMap; +/// # use combine::{Parser, Stream, many1, token, value, unexpected_any, optional, choice}; +/// # use combine::parser::char::digit; +/// # use combine::parser::sequence::loop_parser; +/// # fn main() { +/// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count +/// #[derive(PartialEq, Eq, Clone, Hash)] +/// enum Token { A, B, C } +/// fn token_parser(last_token: &Option) -> impl Parser +/// where +/// Input: Stream +/// { +/// let mut choices = vec![]; +/// if *last_token != Some(Token::A) { +/// choices.push(token('a').map(|_| Token::A).left()); +/// } +/// if *last_token != Some(Token::B) { +/// choices.push(token('b').map(|_| Token::B).left().right()); +/// } +/// if *last_token != Some(Token::C) { +/// choices.push(token('c').map(|_| Token::C).right().right()); +/// } +/// choice(choices) +/// } +/// let result = loop_parser((HashMap::::new(), None), |(_, last_token)| { +/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::, Option)| { +/// *acc.entry(current_token.clone()).or_insert(0) += 1; +/// *last_token = Some(current_token); +/// }) +/// }).map(|x| x.0).parse("ababacbcbcaa"); +/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4))); +/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4))); +/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3))); +/// assert_eq!(result.as_ref().map(|x| x.1), Ok("a")); +/// # } +/// ``` +pub fn loop_parser(state: S, func: F) -> Loop +where + Input: Stream, + F: FnMut(&mut S) -> P, + P: Parser, + G: FnOnce(&mut S), + S: Clone +{ + Loop(func, state) +} + +#[derive(Copy, Clone)] +pub struct LoopGen(F, G); + +impl Parser for LoopGen +where + Input: Stream, + F: FnMut(&mut S) -> P, + G: FnMut() -> S, + P: Parser, + H: FnOnce(&mut S) +{ + type Output = S; + type PartialState = (Option, Option

, bool, P::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 Self(ref mut next_func, ref mut state_gen) = *self; + let (ref mut state, ref mut parser, ref mut committed, ref mut partial_state) = *state; + if mode.is_first() { + debug_assert!(state.is_none()); + debug_assert!(parser.is_none()); + debug_assert!(!*committed); + *state = Some(state_gen()); + *parser = Some(next_func(state.as_mut().unwrap())); + } + let parser = parser.as_mut().unwrap(); + loop { + let before = input.checkpoint(); + let result = parser.parse_mode_impl(mode, input, partial_state); + let mutator = match result { + CommitOk(next_mutator) => { + *committed = true; + next_mutator + }, + PeekOk(next_mutator) => next_mutator, + CommitErr(e) => return CommitErr(e), + PeekErr(_) => { + match input.reset(before) { + Ok(_) => if *committed { + return CommitOk(state.take().unwrap()) + } else { + return PeekOk(state.take().unwrap()) + }, + Err(err) => return CommitErr(err) + }; + } + }; + let state = state.as_mut().unwrap(); + mutator(state); + *parser = next_func(state); + *partial_state = Default::default(); + mode.set_first(); + } + } +} + +// Takes a function `func` and initial `state`. Function is applied to current +// state and generates a parser outputting function to update the state. This +// is repeated until the generated parser fails. +// +/// ``` +/// # extern crate combine; +/// # use std::collections::HashMap; +/// # use combine::{Parser, Stream, many1, token, value, unexpected_any, optional, choice}; +/// # use combine::parser::char::digit; +/// # use combine::parser::sequence::loop_gen; +/// # fn main() { +/// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count +/// #[derive(PartialEq, Eq, Clone, Hash)] +/// enum Token { A, B, C } +/// fn token_parser(last_token: &Option) -> impl Parser +/// where +/// Input: Stream +/// { +/// let mut choices = vec![]; +/// if *last_token != Some(Token::A) { +/// choices.push(token('a').map(|_| Token::A).left()); +/// } +/// if *last_token != Some(Token::B) { +/// choices.push(token('b').map(|_| Token::B).left().right()); +/// } +/// if *last_token != Some(Token::C) { +/// choices.push(token('c').map(|_| Token::C).right().right()); +/// } +/// choice(choices) +/// } +/// let result = loop_gen(|| (HashMap::::new(), None), |(_, last_token)| { +/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::, Option)| { +/// *acc.entry(current_token.clone()).or_insert(0) += 1; +/// *last_token = Some(current_token); +/// }) +/// }).map(|x| x.0).parse("ababacbcbcaa"); +/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4))); +/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4))); +/// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3))); +/// assert_eq!(result.as_ref().map(|x| x.1), Ok("a")); +/// # } +/// ``` +pub fn loop_gen(state_gen: G, func: F) -> LoopGen +where + Input: Stream, + F: FnMut(&mut S) -> P, + G: FnMut() -> S, + P: Parser, + H: FnOnce(&mut S) +{ + LoopGen(func, state_gen) +} From df6a76e807775766342a5edc4d81f8e3f4a7b6c0 Mon Sep 17 00:00:00 2001 From: Maciej Piechotka Date: Tue, 29 Jun 2021 22:52:59 -0700 Subject: [PATCH 3/4] fixup! Add loop_parser and loop_gen --- src/parser/sequence.rs | 141 +++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 27 deletions(-) diff --git a/src/parser/sequence.rs b/src/parser/sequence.rs index 5a6b6d4e..8e895120 100644 --- a/src/parser/sequence.rs +++ b/src/parser/sequence.rs @@ -785,17 +785,6 @@ where ThenPartial(p, f) } -#[cfg(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 @@ -893,9 +882,9 @@ where } #[derive(Copy, Clone)] -pub struct Loop(F, S); +pub struct Loop(F, S, Option

); -impl Parser for Loop +impl Parser for Loop where Input: Stream, F: FnMut(&mut S) -> P, @@ -904,7 +893,7 @@ where G: FnOnce(&mut S) { type Output = S; - type PartialState = (Option, Option

, bool, P::PartialState); + type PartialState = (Option, bool, P::PartialState); parse_mode!(Input); #[inline] @@ -917,8 +906,29 @@ where where M: ParseMode, { - let Self(ref mut next_func, ref init_state) = *self; - LoopGen(next_func, || init_state.clone()).parse_mode_impl(mode, input, state) + let Self(ref mut next_func, ref init_state, ref mut parser) = *self; + let mut lg = LoopGen(next_func, || init_state.clone(), parser.take()); + let result = lg.parse_mode_impl(mode, input, state); + *parser = lg.2; + result + } + + fn add_error(&mut self, errors: &mut Tracked<::Error>) { + if let Some(parser) = &mut self.2 { + parser.add_error(errors); + } + } + + fn add_committed_expected_error(&mut self, errors: &mut Tracked<::Error>) { + self.add_error(errors); + } + + fn parser_count(&self) -> ErrorOffset { + if let Some(parser) = &self.2 { + parser.parser_count() + } else { + ErrorOffset(1) + } } } @@ -964,7 +974,7 @@ where /// assert_eq!(result.as_ref().map(|x| x.1), Ok("a")); /// # } /// ``` -pub fn loop_parser(state: S, func: F) -> Loop +pub fn loop_parser(state: S, func: F) -> Loop where Input: Stream, F: FnMut(&mut S) -> P, @@ -972,13 +982,13 @@ where G: FnOnce(&mut S), S: Clone { - Loop(func, state) + Loop(func, state, None) } #[derive(Copy, Clone)] -pub struct LoopGen(F, G); +pub struct LoopGen(F, G, Option

); -impl Parser for LoopGen +impl Parser for LoopGen where Input: Stream, F: FnMut(&mut S) -> P, @@ -987,7 +997,7 @@ where H: FnOnce(&mut S) { type Output = S; - type PartialState = (Option, Option

, bool, P::PartialState); + type PartialState = (Option, bool, P::PartialState); parse_mode!(Input); #[inline] @@ -1000,8 +1010,8 @@ where where M: ParseMode, { - let Self(ref mut next_func, ref mut state_gen) = *self; - let (ref mut state, ref mut parser, ref mut committed, ref mut partial_state) = *state; + let Self(ref mut next_func, ref mut state_gen, ref mut parser) = *self; + let (ref mut state, ref mut committed, ref mut partial_state) = *state; if mode.is_first() { debug_assert!(state.is_none()); debug_assert!(parser.is_none()); @@ -1038,6 +1048,24 @@ where mode.set_first(); } } + + fn add_error(&mut self, errors: &mut Tracked<::Error>) { + if let Some(parser) = &mut self.2 { + parser.add_error(errors); + } + } + + fn add_committed_expected_error(&mut self, errors: &mut Tracked<::Error>) { + self.add_error(errors); + } + + fn parser_count(&self) -> ErrorOffset { + if let Some(parser) = &self.2 { + parser.parser_count() + } else { + ErrorOffset(1) + } + } } // Takes a function `func` and initial `state`. Function is applied to current @@ -1047,8 +1075,7 @@ where /// ``` /// # extern crate combine; /// # use std::collections::HashMap; -/// # use combine::{Parser, Stream, many1, token, value, unexpected_any, optional, choice}; -/// # use combine::parser::char::digit; +/// # use combine::{Parser, Stream, token, choice}; /// # use combine::parser::sequence::loop_gen; /// # fn main() { /// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count @@ -1082,7 +1109,7 @@ where /// assert_eq!(result.as_ref().map(|x| x.1), Ok("a")); /// # } /// ``` -pub fn loop_gen(state_gen: G, func: F) -> LoopGen +pub fn loop_gen(state_gen: G, func: F) -> LoopGen where Input: Stream, F: FnMut(&mut S) -> P, @@ -1090,5 +1117,65 @@ where P: Parser, H: FnOnce(&mut S) { - LoopGen(func, state_gen) + LoopGen(func, state_gen, None) +} + + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use crate::{Parser, Stream, token, choice, eof}; + use crate::parser::{token::any, EasyParser}; + use crate::parser::sequence::loop_gen; + use crate::stream::easy::{Info, Error}; + + #[test] + fn sequence_single_parser() { + assert!((any(),).easy_parse("a").is_ok()); + } + + #[test] + fn loop_gen_error() { + #[derive(PartialEq, Eq, Clone, Debug, Hash)] + enum Token { A, B, C } + fn token_parser(last_token: &Option) -> impl Parser + where + Input: Stream + { + let mut choices = vec![]; + if *last_token != Some(Token::A) { + choices.push(token('a').map(|_| Token::A).left()); + } + if *last_token != Some(Token::B) { + choices.push(token('b').map(|_| Token::B).left().right()); + } + if *last_token != Some(Token::C) { + choices.push(token('c').map(|_| Token::C).right().right()); + } + choice(choices) + } + let string = "ababacbcbcaa"; + let result = ( + loop_gen(|| (HashMap::::new(), None), |(_, last_token)| { + token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::, Option)| { + *acc.entry(current_token.clone()).or_insert(0) += 1; + *last_token = Some(current_token); + }) + }), + eof() + ).easy_parse(string); + let result = result.as_ref(); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!( + err.errors, + vec![ + Error::Unexpected(Info::Token('a')), + Error::Expected(Info::Token('b')), + Error::Expected(Info::Token('c')), + Error::Expected(Info::Static("end of input")) + ] + ); + assert_eq!(11, err.position.translate_position(string)); + } } From 7f1ad4e5ce416b413419fbf157bea7cc8c409ee7 Mon Sep 17 00:00:00 2001 From: Maciej Piechotka Date: Sun, 4 Jul 2021 11:46:15 -0700 Subject: [PATCH 4/4] fixup! Add loop_parser and loop_gen --- src/parser/sequence.rs | 102 ++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/parser/sequence.rs b/src/parser/sequence.rs index 8e895120..f0fd965d 100644 --- a/src/parser/sequence.rs +++ b/src/parser/sequence.rs @@ -882,15 +882,15 @@ where } #[derive(Copy, Clone)] -pub struct Loop(F, S, Option

); +pub struct Loop(F, G, S, Option

); -impl Parser for Loop +impl Parser for Loop where Input: Stream, F: FnMut(&mut S) -> P, S: Clone, - P: Parser, - G: FnOnce(&mut S) + P: Parser, + G: FnMut(&mut S, P::Output) { type Output = S; type PartialState = (Option, bool, P::PartialState); @@ -906,15 +906,15 @@ where where M: ParseMode, { - let Self(ref mut next_func, ref init_state, ref mut parser) = *self; - let mut lg = LoopGen(next_func, || init_state.clone(), parser.take()); + let Self(ref mut next_func, ref mut state_gen, ref mut init_state, ref mut parser) = *self; + let mut lg: LoopGen<&mut F, _, &mut G, P> = LoopGen(next_func, || init_state.clone(), state_gen, parser.take()); let result = lg.parse_mode_impl(mode, input, state); - *parser = lg.2; + *parser = lg.3; result } fn add_error(&mut self, errors: &mut Tracked<::Error>) { - if let Some(parser) = &mut self.2 { + if let Some(parser) = &mut self.3 { parser.add_error(errors); } } @@ -924,7 +924,7 @@ where } fn parser_count(&self) -> ErrorOffset { - if let Some(parser) = &self.2 { + if let Some(parser) = &self.3 { parser.parser_count() } else { ErrorOffset(1) @@ -946,7 +946,8 @@ where /// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count /// #[derive(PartialEq, Eq, Clone, Hash)] /// enum Token { A, B, C } -/// fn token_parser(last_token: &Option) -> impl Parser +/// type State = (HashMap::, Option); +/// fn token_parser((_, last_token): &mut State) -> impl Parser /// where /// Input: Stream /// { @@ -962,39 +963,38 @@ where /// } /// choice(choices) /// } -/// let result = loop_parser((HashMap::::new(), None), |(_, last_token)| { -/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::, Option)| { -/// *acc.entry(current_token.clone()).or_insert(0) += 1; -/// *last_token = Some(current_token); -/// }) -/// }).map(|x| x.0).parse("ababacbcbcaa"); +/// fn update_state((ref mut acc, ref mut last_token): &mut State, current_token: Token) { +/// *acc.entry(current_token.clone()).or_insert(0) += 1; +/// *last_token = Some(current_token); +/// } +/// let result = loop_parser((HashMap::::new(), None), token_parser, update_state).map(|x| x.0).parse("ababacbcbcaa"); /// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4))); /// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4))); /// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3))); /// assert_eq!(result.as_ref().map(|x| x.1), Ok("a")); /// # } /// ``` -pub fn loop_parser(state: S, func: F) -> Loop +pub fn loop_parser(init_state: S, next_parser: F, mutator: G) -> Loop where Input: Stream, F: FnMut(&mut S) -> P, - P: Parser, - G: FnOnce(&mut S), - S: Clone + S: Clone, + P: Parser, + G: FnMut(&mut S, P::Output) { - Loop(func, state, None) + Loop(next_parser, mutator, init_state, None) } #[derive(Copy, Clone)] -pub struct LoopGen(F, G, Option

); +pub struct LoopGen(F, G, H, Option

); -impl Parser for LoopGen +impl Parser for LoopGen where Input: Stream, F: FnMut(&mut S) -> P, G: FnMut() -> S, - P: Parser, - H: FnOnce(&mut S) + P: Parser, + H: FnMut(&mut S, P::Output) { type Output = S; type PartialState = (Option, bool, P::PartialState); @@ -1010,7 +1010,7 @@ where where M: ParseMode, { - let Self(ref mut next_func, ref mut state_gen, ref mut parser) = *self; + let Self(ref mut next_func, ref mut state_gen, ref mut mutator, ref mut parser) = *self; let (ref mut state, ref mut committed, ref mut partial_state) = *state; if mode.is_first() { debug_assert!(state.is_none()); @@ -1023,12 +1023,12 @@ where loop { let before = input.checkpoint(); let result = parser.parse_mode_impl(mode, input, partial_state); - let mutator = match result { - CommitOk(next_mutator) => { + let value = match result { + CommitOk(next_value) => { *committed = true; - next_mutator + next_value }, - PeekOk(next_mutator) => next_mutator, + PeekOk(next_value) => next_value, CommitErr(e) => return CommitErr(e), PeekErr(_) => { match input.reset(before) { @@ -1042,7 +1042,7 @@ where } }; let state = state.as_mut().unwrap(); - mutator(state); + mutator(state, value); *parser = next_func(state); *partial_state = Default::default(); mode.set_first(); @@ -1050,7 +1050,7 @@ where } fn add_error(&mut self, errors: &mut Tracked<::Error>) { - if let Some(parser) = &mut self.2 { + if let Some(parser) = &mut self.3 { parser.add_error(errors); } } @@ -1060,7 +1060,7 @@ where } fn parser_count(&self) -> ErrorOffset { - if let Some(parser) = &self.2 { + if let Some(parser) = &self.3 { parser.parser_count() } else { ErrorOffset(1) @@ -1081,7 +1081,8 @@ where /// // Parses 'a', 'b' and 'c' such that there is no consecutive letters returning their count /// #[derive(PartialEq, Eq, Clone, Hash)] /// enum Token { A, B, C } -/// fn token_parser(last_token: &Option) -> impl Parser +/// type State = (HashMap::, Option); +/// fn token_parser((_, last_token): &mut State) -> impl Parser /// where /// Input: Stream /// { @@ -1097,27 +1098,26 @@ where /// } /// choice(choices) /// } -/// let result = loop_gen(|| (HashMap::::new(), None), |(_, last_token)| { -/// token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::, Option)| { -/// *acc.entry(current_token.clone()).or_insert(0) += 1; -/// *last_token = Some(current_token); -/// }) -/// }).map(|x| x.0).parse("ababacbcbcaa"); +/// fn update_state((ref mut acc, ref mut last_token): &mut State, current_token: Token) { +/// *acc.entry(current_token.clone()).or_insert(0) += 1; +/// *last_token = Some(current_token); +/// } +/// let result = loop_gen(|| (HashMap::::new(), None), token_parser, update_state).map(|x| x.0).parse("ababacbcbcaa"); /// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::A)), Ok(Some(&4))); /// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::B)), Ok(Some(&4))); /// assert_eq!(result.as_ref().map(|x| x.0.get(&Token::C)), Ok(Some(&3))); /// assert_eq!(result.as_ref().map(|x| x.1), Ok("a")); /// # } /// ``` -pub fn loop_gen(state_gen: G, func: F) -> LoopGen +pub fn loop_gen(state_gen: G, next_parser: F, mutator: H) -> LoopGen where Input: Stream, F: FnMut(&mut S) -> P, G: FnMut() -> S, - P: Parser, - H: FnOnce(&mut S) + P: Parser, + H: FnMut(&mut S, P::Output) { - LoopGen(func, state_gen, None) + LoopGen(next_parser, state_gen, mutator, None) } @@ -1138,7 +1138,8 @@ mod tests { fn loop_gen_error() { #[derive(PartialEq, Eq, Clone, Debug, Hash)] enum Token { A, B, C } - fn token_parser(last_token: &Option) -> impl Parser + type State = (HashMap::, Option); + fn token_parser((_, last_token): &mut State) -> impl Parser where Input: Stream { @@ -1154,14 +1155,13 @@ mod tests { } choice(choices) } + fn update_state((ref mut acc, ref mut last_token): &mut State, current_token: Token) { + *acc.entry(current_token.clone()).or_insert(0) += 1; + *last_token = Some(current_token); + } let string = "ababacbcbcaa"; let result = ( - loop_gen(|| (HashMap::::new(), None), |(_, last_token)| { - token_parser(last_token).map(|current_token| move |(ref mut acc, ref mut last_token): &mut (HashMap::, Option)| { - *acc.entry(current_token.clone()).or_insert(0) += 1; - *last_token = Some(current_token); - }) - }), + loop_gen(|| (HashMap::::new(), None), token_parser, update_state), eof() ).easy_parse(string); let result = result.as_ref();