use nom::bytes::complete::take; use nom::combinator::not; use nom::error::VerboseError; use nom::IResult; use super::list::List; type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>; #[derive(Debug, Clone)] pub struct ContextTree<'r> { tree: List>, } impl<'r> ContextTree<'r> { pub fn new() -> Self { ContextTree { tree: List::new() } } pub fn with_additional_node(&self, data: ContextElement<'r>) -> ContextTree<'r> { let new_list = self.tree.push_front(data); ContextTree { tree: new_list } } pub fn check_fail_matcher<'s>( &'r self, i: &'s str, ) -> IResult<&'s str, &'s str, VerboseError<&'s str>> { // TODO: Can I do this without incrementing reference counters? Perhaps via implementing an iterator over the list? let mut current_node = self.tree.clone(); while !current_node.is_empty() { let context_element = current_node .get_data() .expect("While looop proves its Some()"); match context_element { ContextElement::FailMatcherNode(fail_matcher) => { match fail_matcher.fail_matcher { ChainBehavior::AndParent(Some(matcher)) => { let local_result = matcher(i); if local_result.is_ok() { return local_result; } } ChainBehavior::AndParent(None) => {} ChainBehavior::IgnoreParent(Some(matcher)) => { let local_result = matcher(i); if local_result.is_ok() { return local_result; } // TODO: Make this a custom error not(take(0usize))(i)?; } ChainBehavior::IgnoreParent(None) => { // TODO: Make this a custom error not(take(0usize))(i)?; } }; } ContextElement::PreviousElementNode(_) => todo!(), }; current_node = current_node.without_front(); } // TODO: Make this a custom error not(take(0usize))(i)?; unreachable!() } } #[derive(Debug, Clone)] pub enum ContextElement<'r> { FailMatcherNode(FailMatcherNode<'r>), PreviousElementNode(PreviousElementNode<'r>), } #[derive(Debug, Clone)] pub struct FailMatcherNode<'r> { pub fail_matcher: ChainBehavior<'r>, } #[derive(Debug, Clone)] pub struct PreviousElementNode<'r> { pub dummy: &'r str, } #[derive(Clone)] pub enum ChainBehavior<'r> { AndParent(Option<&'r Matcher>), IgnoreParent(Option<&'r Matcher>), } impl<'r> std::fmt::Debug for ChainBehavior<'r> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut formatter = f.debug_struct("ChainBehavior"); // match self { // ChainBehavior::AndParent(_) => { // formatter = formatter.field("type", &"AndParent"); // } // ChainBehavior::IgnoreParent(_) => { // formatter = formatter.field("type", &"IgnoreParent"); // } // }; formatter.finish() } }