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-11-24 16:24:49 -05:00
|
|
|
use nom::bytes::complete::take;
|
2022-10-15 14:04:24 -04:00
|
|
|
use nom::combinator::not;
|
2022-11-24 16:24:49 -05:00
|
|
|
use nom::error::ContextError;
|
|
|
|
use nom::error::ErrorKind;
|
|
|
|
use nom::error::ParseError;
|
2022-07-15 23:26:49 -04:00
|
|
|
use nom::error::VerboseError;
|
2022-07-16 16:31:00 -04:00
|
|
|
use nom::IResult;
|
2022-10-15 00:01:37 -04:00
|
|
|
use nom::Parser;
|
|
|
|
|
2022-11-24 15:06:07 -05:00
|
|
|
type Link<'r, T> = Option<&'r Node<'r, T>>;
|
2022-11-24 14:59:37 -05:00
|
|
|
type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>;
|
2022-11-24 15:40:07 -05:00
|
|
|
pub type OrgModeContext<'r> = ContextTree<'r, ContextElement<'r>>;
|
2022-11-24 14:59:37 -05:00
|
|
|
|
2022-11-24 15:08:43 -05:00
|
|
|
struct Node<'r, T> {
|
2022-11-24 14:59:37 -05:00
|
|
|
elem: T,
|
2022-11-24 15:06:07 -05:00
|
|
|
next: Link<'r, T>,
|
2022-11-24 14:59:37 -05:00
|
|
|
}
|
|
|
|
|
2022-11-24 15:10:13 -05:00
|
|
|
pub struct ContextTree<'r, T> {
|
2022-11-24 15:08:43 -05:00
|
|
|
head: Option<Node<'r, T>>,
|
2022-11-24 14:59:37 -05:00
|
|
|
}
|
|
|
|
|
2022-11-24 15:10:13 -05:00
|
|
|
impl<'r, T> ContextTree<'r, T> {
|
2022-11-24 14:59:37 -05:00
|
|
|
pub fn new() -> Self {
|
2022-11-24 15:10:13 -05:00
|
|
|
ContextTree { head: None }
|
2022-11-24 14:59:37 -05:00
|
|
|
}
|
|
|
|
|
2022-11-24 15:10:13 -05:00
|
|
|
pub fn with_additional_node(&'r self, element: T) -> ContextTree<'r, T> {
|
2022-11-24 15:06:07 -05:00
|
|
|
let new_node = Node {
|
2022-11-24 14:59:37 -05:00
|
|
|
elem: element,
|
2022-11-24 15:08:43 -05:00
|
|
|
next: self.head.as_ref(),
|
2022-11-24 15:06:07 -05:00
|
|
|
};
|
2022-11-24 14:59:37 -05:00
|
|
|
|
2022-11-24 15:10:13 -05:00
|
|
|
ContextTree {
|
2022-11-24 15:08:43 -05:00
|
|
|
head: Some(new_node),
|
|
|
|
}
|
2022-11-24 14:59:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-24 15:14:53 -05:00
|
|
|
pub struct ContextElement<'r> {
|
|
|
|
pub fail_matcher: ChainBehavior<'r>,
|
2022-11-24 14:59:37 -05:00
|
|
|
}
|
|
|
|
|
2022-11-24 15:14:53 -05:00
|
|
|
pub enum ChainBehavior<'r> {
|
2022-11-24 14:59:37 -05:00
|
|
|
AndParent(Option<&'r Matcher>),
|
|
|
|
IgnoreParent(Option<&'r Matcher>),
|
|
|
|
}
|
2022-11-24 15:40:07 -05:00
|
|
|
|
|
|
|
pub trait OrgModeContextTree<'r> {
|
|
|
|
fn with_additional_fail_matcher(&'r self, fail_matcher: &'r Matcher) -> OrgModeContext<'r>;
|
2022-11-24 16:01:52 -05:00
|
|
|
|
|
|
|
fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>;
|
2022-11-24 15:40:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'r> OrgModeContextTree<'r> for OrgModeContext<'r> {
|
|
|
|
fn with_additional_fail_matcher(
|
|
|
|
&'r self,
|
|
|
|
fail_matcher: &'r Matcher,
|
|
|
|
) -> ContextTree<'r, ContextElement<'r>> {
|
|
|
|
self.with_additional_node(ContextElement {
|
|
|
|
fail_matcher: ChainBehavior::AndParent(Some(fail_matcher)),
|
|
|
|
})
|
|
|
|
}
|
2022-11-24 16:01:52 -05:00
|
|
|
|
|
|
|
fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>> {
|
|
|
|
let mut current_node = self.head.as_ref();
|
|
|
|
while current_node.is_some() {
|
2022-11-24 16:24:49 -05:00
|
|
|
let current_node_unwrapped = current_node
|
|
|
|
.as_ref()
|
|
|
|
.expect("while loop asserts current_node is some.");
|
2022-11-24 16:01:52 -05:00
|
|
|
match current_node_unwrapped.elem.fail_matcher {
|
|
|
|
ChainBehavior::AndParent(Some(matcher)) => {
|
|
|
|
let local_result = matcher(i);
|
|
|
|
if local_result.is_ok() {
|
|
|
|
return local_result;
|
|
|
|
}
|
2022-11-24 16:24:49 -05:00
|
|
|
}
|
|
|
|
ChainBehavior::AndParent(None) => {}
|
|
|
|
ChainBehavior::IgnoreParent(Some(matcher)) => {
|
|
|
|
let local_result = matcher(i);
|
|
|
|
if local_result.is_ok() {
|
|
|
|
return local_result;
|
|
|
|
}
|
|
|
|
// TODO: Make this a custom error
|
|
|
|
not(take(0usize))(i)?;
|
|
|
|
}
|
|
|
|
ChainBehavior::IgnoreParent(None) => {
|
|
|
|
// TODO: Make this a custom error
|
|
|
|
not(take(0usize))(i)?;
|
|
|
|
}
|
2022-11-24 16:01:52 -05:00
|
|
|
};
|
|
|
|
current_node = current_node.map(|current_head| current_head.next).flatten();
|
|
|
|
}
|
2022-11-24 16:24:49 -05:00
|
|
|
// TODO: Make this a custom error
|
|
|
|
not(take(0usize))(i)?;
|
|
|
|
unreachable!()
|
2022-11-24 16:01:52 -05:00
|
|
|
}
|
2022-11-24 15:40:07 -05:00
|
|
|
}
|