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:
parent
6b93e1c007
commit
30d6648590
1
language_rules.txt
Normal file
1
language_rules.txt
Normal file
@ -0,0 +1 @@
|
||||
Two line breaks to end paragraph except in code blocks
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user