From d2a37ea0755e0814e5b0def0788fbb17a2b2f8e7 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sat, 28 Oct 2023 17:22:01 +0200 Subject: [PATCH 1/4] experimental state management --- src/lib.rs | 2 + src/state/mod.rs | 133 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 src/state/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 295710192..2ab5c5f36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -462,6 +462,8 @@ mod str; pub mod number; +pub mod state; + #[cfg(all(feature = "std", any(doc, doctest, feature = "docsrs")))] #[cfg_attr(any(doc, doctest, feature = "docsrs"), doc = include_str!("../doc/nom_recipes.md"))] pub mod recipes {} diff --git a/src/state/mod.rs b/src/state/mod.rs new file mode 100644 index 000000000..1e9440fd4 --- /dev/null +++ b/src/state/mod.rs @@ -0,0 +1,133 @@ +//! Tools to carry state through a parser + +use core::{ + any::{Any, TypeId}, + cell::RefCell, + ops::ControlFlow, +}; +use std::{collections::HashMap, thread_local}; + +use crate::{error::ParseError, internal::Err, IResult, OutputM, OutputMode, PResult, Parser}; + +thread_local!( + static STATES: RefCell>> = RefCell::new(HashMap::new()); +); + +/// TODO +pub struct State { + initial: T, + parser: F, +} + +///create +pub fn state, F, T: Clone + 'static>( + initial_state: T, + parser: F, +) -> impl Parser>::Output, Error = E> +where + F: Parser, +{ + let state = State { + initial: initial_state.clone(), + parser, + }; + + state +} + +///on input +pub fn on_input, F, G>( + mut parser: F, + mut map: G, +) -> impl Parser>::Output, Error = E> +where + F: Parser, + G: FnMut(&mut T, I) -> ControlFlow>::Output, E>, I>, +{ + move |input: I| match State::::update_input(&mut map, input) { + ControlFlow::Continue(i) => parser.parse(i), + ControlFlow::Break(result) => result, + } +} + +impl State { + fn update_input(mut fun: G, input: Input) -> Res + where + G: FnMut(&mut T, Input) -> Res, + { + STATES.with(|states| { + let mut h = states.borrow_mut(); + let v = h.get_mut(&TypeId::of::()); + let value = v.unwrap(); + + fun(value.downcast_mut::().unwrap(), input) + }) + } + + fn reset(&self) { + STATES.with(|states| { + let mut h = states.borrow_mut(); + h.insert(TypeId::of::(), Box::new(self.initial.clone())); + }) + } +} + +impl Parser for State +where + F: Parser, +{ + type Output = >::Output; + + type Error = >::Error; + + #[inline(always)] + fn process(&mut self, input: I) -> PResult { + self.reset(); + match self + .parser + .process::>(input) + { + Err(Err::Error(e)) => Err(Err::Error(e)), + Err(Err::Failure(e)) => Err(Err::Failure(e)), + Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), + Ok((i, o)) => Ok((i, o)), + } + } +} + +#[cfg(test)] +mod tests { + use crate::{branch::alt, bytes::complete::tag, sequence::preceded}; + + use super::*; + + #[test] + fn state_update() { + fn a(i: &str) -> IResult<&str, &str, ()> { + on_input::(preceded(tag("a"), b), |state, input| { + println!("state = {state}, input = {input}"); + if *state == 3 { + println!("returning Failure"); + ControlFlow::Break(Err(Err::Failure(()))) + } else { + *state += 1; + ControlFlow::Continue(input) + } + }) + .parse(i) + } + + fn b(i: &str) -> IResult<&str, &str, ()> { + preceded(tag("b"), alt((a, tag(".")))).parse(i) + } + + let mut parser = state(0u8, a); + + assert_eq!(parser.parse("abababab"), Err(Err::Failure(()))); + + assert_eq!(parser.parse("abab."), Ok(("", "."))); + } + + #[test] + fn multistate() {} +} From cfe50facc15f0202ae906be33706bed2d5acd5bb Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sat, 28 Oct 2023 17:23:22 +0200 Subject: [PATCH 2/4] remove debug statements --- src/state/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/state/mod.rs b/src/state/mod.rs index 1e9440fd4..7cf753083 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -105,9 +105,7 @@ mod tests { fn state_update() { fn a(i: &str) -> IResult<&str, &str, ()> { on_input::(preceded(tag("a"), b), |state, input| { - println!("state = {state}, input = {input}"); if *state == 3 { - println!("returning Failure"); ControlFlow::Break(Err(Err::Failure(()))) } else { *state += 1; From cc7f3385ce36d63dfbca80a031614a9984b31cc0 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 1 Nov 2023 21:20:33 +0100 Subject: [PATCH 3/4] on_input --- src/state/mod.rs | 187 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 11 deletions(-) diff --git a/src/state/mod.rs b/src/state/mod.rs index 7cf753083..451f47a53 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -3,6 +3,7 @@ use core::{ any::{Any, TypeId}, cell::RefCell, + marker::PhantomData, ops::ControlFlow, }; use std::{collections::HashMap, thread_local}; @@ -14,7 +15,7 @@ thread_local!( ); /// TODO -pub struct State { +pub struct InitialState { initial: T, parser: F, } @@ -27,7 +28,7 @@ pub fn state, F, T: Clone + 'static>( where F: Parser, { - let state = State { + let state = InitialState { initial: initial_state.clone(), parser, }; @@ -36,21 +37,133 @@ where } ///on input -pub fn on_input, F, G>( +pub fn on_input( mut parser: F, mut map: G, -) -> impl Parser>::Output, Error = E> +) -> impl Parser>::Output, Error = >::Error> where - F: Parser, - G: FnMut(&mut T, I) -> ControlFlow>::Output, E>, I>, + F: Parser, + G: FnMut( + &mut T, + I, + ) -> ControlFlow>::Output, >::Error>, I>, { - move |input: I| match State::::update_input(&mut map, input) { + move |input: I| match InitialState::::update_input(&mut map, input) { ControlFlow::Continue(i) => parser.parse(i), ControlFlow::Break(result) => result, } } -impl State { +fn st(input: Input, parser: P) -> StateParser +//impl Parser>::Output, Error =

>::Error> +where + P: Parser, +{ + StateParser { + parser, + st: PhantomData, + } +} + +struct StateParser { + parser: P, + st: PhantomData, +} + +impl Parser for StateParser +where + P: Parser, +{ + type Output =

>::Output; + + type Error =

>::Error; + + fn process( + &mut self, + input: Input, + ) -> PResult { + todo!() + } +} + +/* +fn st2(f: F) -> impl Parser +where + F: FnMut(State, Input) -> PResult, +{ + todo!() +} +*/ + +/* +trait StateTrait: Parser { + fn on_input( + map: G, + ) -> impl Parser>::Output, Error = >::Error> + where + G: FnMut( + &mut T, + I, + ) + -> ControlFlow>::Output, >::Error>, I>; +} + +impl StateTrait for P +where + P: Parser, +{ + fn on_input( + mut map: G, + ) -> impl Parser>::Output, Error = >::Error> + where + G: FnMut( + &mut T, + I, + ) + -> ControlFlow>::Output, >::Error>, I>, + { + move |input: I| match InitialState::::update_input(&mut map, input) { + ControlFlow::Continue(i) => parser.parse(i), + ControlFlow::Break(result) => result, + } + } +}*/ + +struct StateInput { + parser: P, + f: F, + st: PhantomData, +} + +impl Parser for StateInput +where + P: Parser, + F: FnMut( + &mut State, + Input, + ) -> ControlFlow< + IResult>::Output, >::Error>, + Input, + >, +{ + type Output =

>::Output; + + type Error =

>::Error; + + fn process( + &mut self, + input: Input, + ) -> PResult { + match InitialState::::update_input(&mut self.f, input) { + ControlFlow::Continue(i) => self + .parser + .process::>(i), + ControlFlow::Break(result) => result, + } + } +} + +impl InitialState { fn update_input(mut fun: G, input: Input) -> Res where G: FnMut(&mut T, Input) -> Res, @@ -72,7 +185,7 @@ impl State { } } -impl Parser for State +impl Parser for InitialState where F: Parser, { @@ -94,6 +207,33 @@ where } } } +/* +struct StateParser { + fun: F, +} + +impl Parser for StateParser +where + F: FnMut(State, I) -> Parser, +{ + type Output = >::Output; + + type Error = >::Error; + + #[inline(always)] + fn process(&mut self, input: I) -> PResult { + self.reset(); + match self + .parser + .process::>(input) + { + Err(Err::Error(e)) => Err(Err::Error(e)), + Err(Err::Failure(e)) => Err(Err::Failure(e)), + Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)), + Ok((i, o)) => Ok((i, o)), + } + } +}*/ #[cfg(test)] mod tests { @@ -104,7 +244,7 @@ mod tests { #[test] fn state_update() { fn a(i: &str) -> IResult<&str, &str, ()> { - on_input::(preceded(tag("a"), b), |state, input| { + on_input::(preceded(tag("a"), b), |state, input| { if *state == 3 { ControlFlow::Break(Err(Err::Failure(()))) } else { @@ -127,5 +267,30 @@ mod tests { } #[test] - fn multistate() {} + fn multistate() { + //fn a(i: &str) -> IResult<&str, &str, ()> { + /* + st(|state| { + if state.is_valid() { + preceded(tag("a"), b).map(|o| + //NO! double mutable borrow state.update()) + } + }) + + preceded(tag("a"), b) + .on_input(|state, input| -> ControlFlow) + .on_output(|state, result| -> result) + */ + + /*on_input::(preceded(tag("a"), b), |state, input| { + if *state == 3 { + ControlFlow::Break(Err(Err::Failure(()))) + } else { + *state += 1; + ControlFlow::Continue(input) + } + }) + .parse(i)*/ + //} + } } From ec8fe158224b30073a5ff5b8171c1fc20354c443 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 1 Nov 2023 23:35:16 +0100 Subject: [PATCH 4/4] test --- src/state/mod.rs | 129 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 14 deletions(-) diff --git a/src/state/mod.rs b/src/state/mod.rs index 451f47a53..5eb66294c 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -8,7 +8,9 @@ use core::{ }; use std::{collections::HashMap, thread_local}; -use crate::{error::ParseError, internal::Err, IResult, OutputM, OutputMode, PResult, Parser}; +use crate::{ + error::ParseError, internal::Err, internal::Mode, IResult, OutputM, OutputMode, PResult, Parser, +}; thread_local!( static STATES: RefCell>> = RefCell::new(HashMap::new()); @@ -54,6 +56,26 @@ where } } +/* +///a +pub fn on_output( + mut parser: F, + mut map: G, +) -> impl Parser>::Output, Error = >::Error> +where + F: Parser, + G: FnMut( + &mut T, + I, + ) -> ControlFlow>::Output, >::Error>, I>, +{ + move |input: I| match InitialState::::update_input(&mut map, input) { + ControlFlow::Continue(i) => parser.parse(i), + ControlFlow::Break(result) => result, + } +}*/ + +/* fn st(input: Input, parser: P) -> StateParser //impl Parser>::Output, Error =

>::Error> where @@ -84,7 +106,7 @@ where ) -> PResult { todo!() } -} +}*/ /* fn st2(f: F) -> impl Parser @@ -95,26 +117,25 @@ where } */ -/* trait StateTrait: Parser { - fn on_input( - map: G, - ) -> impl Parser>::Output, Error = >::Error> + fn on_input(self, map: G) -> StateInput where G: FnMut( &mut T, I, ) -> ControlFlow>::Output, >::Error>, I>; + + fn on_output(self, map: G) -> StateOutput + where + G: FnMut(&mut T, >::Output) -> >::Output; } impl StateTrait for P where P: Parser, { - fn on_input( - mut map: G, - ) -> impl Parser>::Output, Error = >::Error> + fn on_input(self, mut map: G) -> StateInput where G: FnMut( &mut T, @@ -122,12 +143,25 @@ where ) -> ControlFlow>::Output, >::Error>, I>, { - move |input: I| match InitialState::::update_input(&mut map, input) { - ControlFlow::Continue(i) => parser.parse(i), - ControlFlow::Break(result) => result, + StateInput { + parser: self, + f: map, + st: PhantomData, } } -}*/ + + fn on_output(self, map: G) -> StateOutput + //impl Parser>::Output, Error = >::Error> + where + G: FnMut(&mut T, >::Output) -> >::Output, + { + StateInput { + parser: self, + f: map, + st: PhantomData, + } + } +} struct StateInput { parser: P, @@ -154,11 +188,43 @@ where &mut self, input: Input, ) -> PResult { - match InitialState::::update_input(&mut self.f, input) { + /*match InitialState::::update_input(&mut self.f, input) { ControlFlow::Continue(i) => self .parser .process::>(i), ControlFlow::Break(result) => result, + }*/ + todo!() + } +} + +struct StateOutput { + parser: P, + f: F, + st: PhantomData, +} + +impl Parser for StateOutput +where + State: Clone + 'static, + P: Parser, + F: FnMut(&mut State,

>::Output) ->

>::Output, //IResult>::Output,

>::Error>, +{ + type Output =

>::Output; + type Error =

>::Error; + + fn process( + &mut self, + input: Input, + ) -> PResult { + match self.parser.process::(input) { + Err(e) => Err(e), + Ok((i, o)) => Ok(( + i, + OM::Output::map(o, move |o| { + InitialState::::update_input(&mut self.f, o) + }), + )), } } } @@ -177,6 +243,19 @@ impl InitialState { }) } + pub(crate) fn update(mut fun: G) + where + G: FnMut(&mut T), + { + STATES.with(|states| { + let mut h = states.borrow_mut(); + let v = h.get_mut(&TypeId::of::()); + let value = v.unwrap(); + + fun(value.downcast_mut::().unwrap()) + }) + } + fn reset(&self) { STATES.with(|states| { let mut h = states.borrow_mut(); @@ -292,5 +371,27 @@ mod tests { }) .parse(i)*/ //} + + fn a(i: &str) -> IResult<&str, &str, ()> { + on_input::(preceded(tag("a"), b), |state, input| { + if *state == 3 { + ControlFlow::Break(Err(Err::Failure(()))) + } else { + *state += 1; + ControlFlow::Continue(input) + } + }) + .parse(i) + } + + fn b(i: &str) -> IResult<&str, &str, ()> { + preceded(tag("b"), alt((a.map(|output| {}), tag(".")))).parse(i) + } + + let mut parser = state(0u8, a); + + assert_eq!(parser.parse("abababab"), Err(Err::Failure(()))); + + assert_eq!(parser.parse("abab."), Ok(("", "."))); } }