From 30d664859077bfc9e55b2b6a99772d483d2c93c2 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 15 Oct 2022 00:39:32 -0400 Subject: [PATCH] Implement logic for checking the fail matchers without keeping mutable borrows open for longer than the execution of that function. --- language_rules.txt | 1 + src/parser/nom_context.rs | 48 ++++++++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 language_rules.txt diff --git a/language_rules.txt b/language_rules.txt new file mode 100644 index 0000000..1144196 --- /dev/null +++ b/language_rules.txt @@ -0,0 +1 @@ +Two line breaks to end paragraph except in code blocks diff --git a/src/parser/nom_context.rs b/src/parser/nom_context.rs index 01900db..18946ad 100644 --- a/src/parser/nom_context.rs +++ b/src/parser/nom_context.rs @@ -6,53 +6,69 @@ use nom::error::VerboseError; use nom::IResult; use nom::Parser; -pub type MatcherInner = Rc IResult<&str, &str, VerboseError<&str>>>>; +type MatcherRef = Rc IResult<&str, &str, VerboseError<&str>>>>; -struct MatcherRef(MatcherInner); +struct FailChecker<'a>(&'a NomContext<'a>); -impl MatcherRef { - pub fn new(func: MatcherInner) -> Self { +impl<'a> FailChecker<'a> { + fn new(func: &'a NomContext<'a>) -> Self { Self(func) } } -// type MatcherRef = Rc IResult<&str, &str, VerboseError<&str>>>>; - enum ChainBehavior { AndParent(Option), IgnoreParent(Option), } pub struct NomContext<'a> { - pub parent: Option<&'a Self>, + parent: Option<&'a Self>, fail_matcher: ChainBehavior, /// You can't have nested bolds or links in org-mode - pub can_match_bold: bool, - pub can_match_link: bool, + can_match_bold: bool, + can_match_link: bool, } impl<'a> NomContext<'a> { - pub fn new(fail_matcher: MatcherInner) -> Self { + pub fn new(fail_matcher: MatcherRef) -> Self { NomContext { parent: None, - fail_matcher: ChainBehavior::IgnoreParent(Some(MatcherRef::new(fail_matcher))), + fail_matcher: ChainBehavior::IgnoreParent(Some(fail_matcher)), can_match_bold: true, can_match_link: true, } } - pub fn with_additional_fail_matcher(&self, other: MatcherInner) -> NomContext { + pub fn with_additional_fail_matcher(&self, other: MatcherRef) -> NomContext { NomContext { parent: Some(&self), - fail_matcher: ChainBehavior::AndParent(Some(MatcherRef::new(other))), + fail_matcher: ChainBehavior::AndParent(Some(other)), can_match_bold: self.can_match_bold, can_match_link: self.can_match_link, } } } -impl Parser<&str, &str, VerboseError<&str>> for MatcherRef { - fn parse(&mut self, i: &str) -> IResult<&str, &str, VerboseError<&str>> { - (&mut *self.0.borrow_mut())(i) +impl<'a, 'b> Parser<&'b str, &'b str, VerboseError<&'b str>> for FailChecker<'a> { + fn parse(&mut self, i: &'b str) -> IResult<&'b str, &'b str, VerboseError<&'b 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) + } + } } }