use std::cell::RefCell; use std::rc::Rc; use nom::branch::alt; use nom::combinator::not; use nom::error::VerboseError; use nom::IResult; use nom::Parser; pub struct TestContext { head: ContextReference, } type ContextReference = Option>>; struct ContextLayer { data: T, parent: ContextReference, } struct ContextData { fail_matcher: ChainBehavior, } impl TestContext { pub fn new() -> Self { TestContext { head: None } } pub fn with_additional_fail_matcher( &self, new_matcher: MatcherRef, ) -> TestContext { TestContext { head: Some(Box::new(ContextLayer { data: ContextData { fail_matcher: ChainBehavior::AndParent(Some(new_matcher)), }, parent: self.head, // TODO FIX THIS })), } } } ///// ///// OLD ///// type MatcherRef = Rc IResult<&str, &str, VerboseError<&str>>>>; struct FailChecker<'r>(&'r NomContext<'r>); impl<'r> FailChecker<'r> { fn new(func: &'r NomContext<'r>) -> Self { Self(func) } } enum ChainBehavior { AndParent(Option), IgnoreParent(Option), } pub struct NomContext<'r> { parent: Option<&'r Self>, fail_matcher: ChainBehavior, /// You can't have nested bolds or links in org-mode match_bold_allowed: bool, match_link_allowed: bool, } impl<'r> NomContext<'r> { pub fn new(fail_matcher: MatcherRef) -> Self { NomContext { parent: None, fail_matcher: ChainBehavior::IgnoreParent(Some(fail_matcher)), match_bold_allowed: true, match_link_allowed: true, } } pub fn with_additional_fail_matcher(&self, other: MatcherRef) -> NomContext { NomContext { parent: Some(&self), fail_matcher: ChainBehavior::AndParent(Some(other)), match_bold_allowed: self.match_bold_allowed, match_link_allowed: self.match_link_allowed, } } pub fn without_bold(&self, other: MatcherRef) -> NomContext { NomContext { parent: Some(&self), fail_matcher: ChainBehavior::AndParent(Some(other)), match_bold_allowed: false, match_link_allowed: self.match_link_allowed, } } pub fn not_matching_fail<'s>(&self, i: &'s str) -> IResult<&'s str, (), VerboseError<&'s str>> { not(FailChecker::new(self))(i) } pub fn can_match_bold(&self) -> bool { self.match_bold_allowed } pub fn can_match_link(&self) -> bool { self.match_link_allowed } } impl<'r, 's> Parser<&'s str, &'s str, VerboseError<&'s str>> for FailChecker<'r> { fn parse(&mut self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>> { let fail_func = match &self.0.fail_matcher { ChainBehavior::AndParent(inner) => inner, ChainBehavior::IgnoreParent(inner) => inner, }; if let Some(inner) = fail_func { let parsed = (&mut *inner.borrow_mut())(i); if parsed.is_ok() { return parsed; } } match (self.0.parent, &self.0.fail_matcher) { (None, _) | (_, ChainBehavior::IgnoreParent(_)) => Err(nom::Err::Error( nom::error::make_error(i, nom::error::ErrorKind::Alt), )), (Some(parent), ChainBehavior::AndParent(_)) => { let mut parent_fail_checker = FailChecker::new(parent); parent_fail_checker.parse(i) } } } }