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..5eb66294c --- /dev/null +++ b/src/state/mod.rs @@ -0,0 +1,397 @@ +//! Tools to carry state through a parser + +use core::{ + any::{Any, TypeId}, + cell::RefCell, + marker::PhantomData, + ops::ControlFlow, +}; +use std::{collections::HashMap, thread_local}; + +use crate::{ + error::ParseError, internal::Err, internal::Mode, IResult, OutputM, OutputMode, PResult, Parser, +}; + +thread_local!( + static STATES: RefCell>> = RefCell::new(HashMap::new()); +); + +/// TODO +pub struct InitialState { + 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 = InitialState { + initial: initial_state.clone(), + parser, + }; + + state +} + +///on input +pub fn on_input( + 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, + } +} + +/* +///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 + 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(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(self, mut map: G) -> StateInput + where + G: FnMut( + &mut T, + I, + ) + -> ControlFlow>::Output, >::Error>, I>, + { + 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, + 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, + }*/ + 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) + }), + )), + } + } +} + +impl InitialState { + 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) + }) + } + + 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(); + h.insert(TypeId::of::(), Box::new(self.initial.clone())); + }) + } +} + +impl Parser for InitialState +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)), + } + } +} +/* +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 { + 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| { + 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, 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() { + //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)*/ + //} + + 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(("", "."))); + } +}