organic/src/parser/nom_context.rs

135 lines
3.9 KiB
Rust
Raw Normal View History

use nom::combinator::not;
2022-11-26 22:03:15 -05:00
use nom::combinator::recognize;
use nom::complete::take;
2022-11-24 16:24:49 -05:00
use nom::error::ErrorKind;
use nom::error::ParseError;
2022-07-15 23:26:49 -04:00
use nom::error::VerboseError;
use nom::IResult;
2022-11-26 22:03:15 -05:00
use std::borrow::Cow;
2022-11-24 14:59:37 -05:00
2022-11-26 22:03:15 -05:00
use super::text::bold_end;
use super::text::Res;
2022-11-24 14:59:37 -05:00
2022-11-26 22:03:15 -05:00
type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>;
type Link<'r, T> = Option<&'r Node<'r, T>>;
pub type OrgModeContextTree<'r> = ContextTree<'r, dyn OrgModeContext<'r>>;
2022-11-24 14:59:37 -05:00
2022-11-26 22:03:15 -05:00
pub trait OrgModeContext<'r> {
fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>>;
2022-11-24 14:59:37 -05:00
}
struct FailMatcherNode<'r> {
2022-11-26 22:03:15 -05:00
fail_matcher: ChainBehavior<'r>,
2022-11-24 14:59:37 -05:00
}
2022-11-26 22:03:15 -05:00
struct PreviousElementNode<'r> {
dummy: &'r str,
}
2022-11-26 22:03:15 -05:00
#[derive(Clone)]
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
2022-11-26 22:03:15 -05:00
struct Node<'r, T: 'r + ?Sized> {
elem: &'r T,
parent: Link<'r, T>,
}
2022-11-26 22:03:15 -05:00
pub struct ContextTree<'r, T: 'r + ?Sized> {
// Not using Link so the ContextTree can own this node
head: Option<Node<'r, T>>,
2022-11-24 15:40:07 -05:00
}
2022-11-26 22:03:15 -05:00
impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> {
pub fn new() -> Self {
ContextTree { head: None }
2022-11-24 15:40:07 -05:00
}
2022-11-26 22:03:15 -05:00
pub fn with_additional_node(
&'r self,
new_elem: &'r dyn OrgModeContext<'r>,
) -> ContextTree<'r, dyn OrgModeContext<'r>> {
let new_node = Node {
elem: new_elem,
parent: self.head.as_ref(),
};
ContextTree {
head: Some(new_node),
}
}
2022-11-26 22:03:15 -05:00
pub fn check_fail_matcher<'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-26 22:03:15 -05:00
let current_node_unwrapped =
current_node.expect("while loop asserts current_node is some.");
let current_fail_matcher = current_node_unwrapped.elem.get_fail_matcher();
match current_fail_matcher.as_ref() {
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)) => {
2022-11-26 22:03:15 -05:00
return matcher(i);
2022-11-24 16:24:49 -05:00
}
ChainBehavior::IgnoreParent(None) => {
// TODO: Make this a custom error
2022-11-26 22:03:15 -05:00
return Err(nom::Err::Error(VerboseError::from_error_kind(
i,
ErrorKind::ManyTill,
)));
2022-11-24 16:24:49 -05:00
}
};
2022-11-26 22:03:15 -05:00
current_node = current_node
.map(|current_head| current_head.parent)
.flatten();
}
2022-11-24 16:24:49 -05:00
// TODO: Make this a custom error
2022-11-26 22:03:15 -05:00
return Err(nom::Err::Error(VerboseError::from_error_kind(
i,
ErrorKind::ManyTill,
)));
}
}
impl<'r> OrgModeContext<'r> for FailMatcherNode<'r> {
fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>> {
Cow::Borrowed(&self.fail_matcher)
}
}
impl<'r> OrgModeContext<'r> for PreviousElementNode<'r> {
fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>> {
Cow::Owned(ChainBehavior::AndParent(None))
}
2022-11-24 15:40:07 -05:00
}
2022-11-25 18:23:51 -05:00
2022-11-26 22:03:15 -05:00
fn recognize_bold_end(input: &str) -> Res<&str, &str> {
recognize(bold_end)(input)
}
fn test_context() {
let foo = "foo";
let context = ContextTree::new();
let child1_context = PreviousElementNode { dummy: foo };
let child1 = context.with_additional_node(&child1_context);
let child2_context = FailMatcherNode {
fail_matcher: ChainBehavior::AndParent(Some(&recognize_bold_end)),
};
let child2 = child1.with_additional_node(&child2_context);
}
2022-11-25 18:23:51 -05:00
impl<'r, T> std::fmt::Debug for ContextTree<'r, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ContextTree")
}
}