organic/src/parser/nom_context.rs

75 lines
2.2 KiB
Rust
Raw Normal View History

2022-10-15 00:01:37 -04:00
use std::cell::RefCell;
use std::rc::Rc;
2022-07-16 17:27:08 -04:00
use nom::branch::alt;
2022-07-15 23:26:49 -04:00
use nom::error::VerboseError;
use nom::IResult;
2022-10-15 00:01:37 -04:00
use nom::Parser;
type MatcherRef = Rc<RefCell<dyn FnMut(&str) -> IResult<&str, &str, VerboseError<&str>>>>;
2022-10-15 00:01:37 -04:00
struct FailChecker<'a>(&'a NomContext<'a>);
2022-10-15 00:01:37 -04:00
impl<'a> FailChecker<'a> {
fn new(func: &'a NomContext<'a>) -> Self {
2022-10-15 00:01:37 -04:00
Self(func)
}
}
enum ChainBehavior {
AndParent(Option<MatcherRef>),
IgnoreParent(Option<MatcherRef>),
}
pub struct NomContext<'a> {
parent: Option<&'a Self>,
2022-10-15 00:01:37 -04:00
fail_matcher: ChainBehavior,
2022-10-14 20:09:09 -04:00
/// You can't have nested bolds or links in org-mode
can_match_bold: bool,
can_match_link: bool,
2022-07-15 23:26:49 -04:00
}
2022-10-15 00:01:37 -04:00
impl<'a> NomContext<'a> {
pub fn new(fail_matcher: MatcherRef) -> Self {
2022-07-16 21:32:23 -04:00
NomContext {
2022-10-15 00:01:37 -04:00
parent: None,
fail_matcher: ChainBehavior::IgnoreParent(Some(fail_matcher)),
2022-07-16 21:55:33 -04:00
can_match_bold: true,
can_match_link: true,
}
}
2022-10-14 20:50:00 -04:00
pub fn with_additional_fail_matcher(&self, other: MatcherRef) -> NomContext {
2022-10-15 00:01:37 -04:00
NomContext {
parent: Some(&self),
fail_matcher: ChainBehavior::AndParent(Some(other)),
2022-10-15 00:01:37 -04:00
can_match_bold: self.can_match_bold,
can_match_link: self.can_match_link,
}
}
}
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)
}
}
2022-10-14 20:50:00 -04:00
}
2022-07-16 21:32:23 -04:00
}