Implement logic for checking the fail matchers without keeping mutable borrows open for longer than the execution of that function.

This commit is contained in:
Tom Alexander 2022-10-15 00:39:32 -04:00
parent 6b93e1c007
commit 30d6648590
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
2 changed files with 33 additions and 16 deletions

1
language_rules.txt Normal file
View File

@ -0,0 +1 @@
Two line breaks to end paragraph except in code blocks

View File

@ -6,53 +6,69 @@ use nom::error::VerboseError;
use nom::IResult;
use nom::Parser;
pub type MatcherInner = Rc<RefCell<dyn FnMut(&str) -> IResult<&str, &str, VerboseError<&str>>>>;
type MatcherRef = Rc<RefCell<dyn FnMut(&str) -> 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<RefCell<dyn FnMut(&str) -> IResult<&str, &str, VerboseError<&str>>>>;
enum ChainBehavior {
AndParent(Option<MatcherRef>),
IgnoreParent(Option<MatcherRef>),
}
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)
}
}
}
}