Revert "Migrating to the new context tree."

This reverts commit c37008df1d41c36780c57054c3d0e0244478c8d5.
This commit is contained in:
Tom Alexander 2022-11-26 22:36:02 -05:00
parent 29add885f3
commit 6e2ff8b870
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
5 changed files with 214 additions and 91 deletions

View File

@ -1,3 +1,4 @@
mod new_context;
mod nom_context; mod nom_context;
mod parser_with_context; mod parser_with_context;
mod text; mod text;

133
src/parser/new_context.rs Normal file
View File

@ -0,0 +1,133 @@
use nom::combinator::not;
use nom::combinator::recognize;
use nom::complete::take;
use nom::error::ErrorKind;
use nom::error::ParseError;
use nom::error::VerboseError;
use nom::IResult;
use std::borrow::Cow;
use super::text::bold_end;
use super::text::Res;
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 trait OrgModeContext<'r> {
fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>>;
}
struct FailMatcherNode<'r> {
fail_matcher: ChainBehavior<'r>,
}
struct PreviousElementNode<'r> {
dummy: &'r str,
}
#[derive(Clone)]
pub enum ChainBehavior<'r> {
AndParent(Option<&'r Matcher>),
IgnoreParent(Option<&'r Matcher>),
}
struct Node<'r, T: 'r + ?Sized> {
elem: &'r T,
parent: Link<'r, T>,
}
struct ContextTree<'r, T: 'r + ?Sized> {
// Not using Link so the ContextTree can own this node
head: Option<Node<'r, T>>,
}
impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> {
pub fn new() -> Self {
ContextTree { head: None }
}
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),
}
}
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() {
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;
}
}
ChainBehavior::AndParent(None) => {}
ChainBehavior::IgnoreParent(Some(matcher)) => {
return matcher(i);
}
ChainBehavior::IgnoreParent(None) => {
// TODO: Make this a custom error
return Err(nom::Err::Error(VerboseError::from_error_kind(
i,
ErrorKind::ManyTill,
)));
}
};
current_node = current_node
.map(|current_head| current_head.parent)
.flatten();
}
// TODO: Make this a custom error
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))
}
}
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);
}
impl<'r, T> std::fmt::Debug for ContextTree<'r, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ContextTree")
}
}

View File

@ -1,75 +1,89 @@
use std::cell::RefCell;
use std::rc::Rc;
use nom::branch::alt;
use nom::bytes::complete::take;
use nom::combinator::not; use nom::combinator::not;
use nom::combinator::recognize; use nom::error::ContextError;
use nom::complete::take;
use nom::error::ErrorKind; use nom::error::ErrorKind;
use nom::error::ParseError; use nom::error::ParseError;
use nom::error::VerboseError; use nom::error::VerboseError;
use nom::IResult; use nom::IResult;
use std::borrow::Cow; use nom::Parser;
use tracing::trace;
use super::text::bold_end;
use super::text::Res;
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>>; type Link<'r, T> = Option<&'r Node<'r, T>>;
pub type OrgModeContextTree<'r> = ContextTree<'r, dyn OrgModeContext<'r>>; type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>;
pub type OrgModeContextNode<'r> = ContextTree<'r, ContextElement<'r>>;
pub trait OrgModeContext<'r> { struct Node<'r, T> {
fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>>; elem: T,
next: Link<'r, T>,
} }
struct FailMatcherNode<'r> { pub struct ContextTree<'r, T> {
fail_matcher: ChainBehavior<'r>, head: Option<Node<'r, T>>,
} }
struct PreviousElementNode<'r> { impl<'r, T> ContextTree<'r, T> {
dummy: &'r str, pub fn new() -> Self {
ContextTree { head: None }
}
pub fn with_additional_node(&'r self, element: T) -> ContextTree<'r, T> {
let new_node = Node {
elem: element,
next: self.head.as_ref(),
};
ContextTree {
head: Some(new_node),
}
}
}
pub struct ContextElement<'r> {
pub fail_matcher: ChainBehavior<'r>,
}
pub struct PreviousElementNode<'r> {
pub dummy: &'r str,
} }
#[derive(Clone)]
pub enum ChainBehavior<'r> { pub enum ChainBehavior<'r> {
AndParent(Option<&'r Matcher>), AndParent(Option<&'r Matcher>),
IgnoreParent(Option<&'r Matcher>), IgnoreParent(Option<&'r Matcher>),
} }
struct Node<'r, T: 'r + ?Sized> { pub trait OrgModeContextTree<'r> {
elem: &'r T, fn with_additional_fail_matcher(&'r self, fail_matcher: &'r Matcher) -> OrgModeContextNode<'r>;
parent: Link<'r, T>,
fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>;
} }
pub struct ContextTree<'r, T: 'r + ?Sized> { impl<'r> OrgModeContextTree<'r> for OrgModeContextNode<'r> {
// Not using Link so the ContextTree can own this node fn with_additional_fail_matcher(
head: Option<Node<'r, T>>, &'r self,
} fail_matcher: &'r Matcher,
) -> ContextTree<'r, ContextElement<'r>> {
impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> { self.with_additional_node(ContextElement {
pub fn new() -> Self { fail_matcher: ChainBehavior::AndParent(Some(fail_matcher)),
ContextTree { head: None } })
} }
pub fn with_additional_node( // fn with_previous_element(&'r self, dummy: &'r str) -> ContextTree<'r, PreviousElementNode<'r>> {
&'r self, // self.with_additional_node(PreviousElementNode {
new_elem: &'r dyn OrgModeContext<'r>, // dummy
) -> ContextTree<'r, dyn OrgModeContext<'r>> { // })
let new_node = Node { // }
elem: new_elem,
parent: self.head.as_ref(),
};
ContextTree {
head: Some(new_node),
}
}
pub fn check_fail_matcher<'s>( fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>> {
&'r self,
i: &'s str,
) -> IResult<&'s str, &'s str, VerboseError<&'s str>> {
let mut current_node = self.head.as_ref(); let mut current_node = self.head.as_ref();
while current_node.is_some() { while current_node.is_some() {
let current_node_unwrapped = let current_node_unwrapped = current_node
current_node.expect("while loop asserts current_node is some."); .as_ref()
let current_fail_matcher = current_node_unwrapped.elem.get_fail_matcher(); .expect("while loop asserts current_node is some.");
match current_fail_matcher.as_ref() { match current_node_unwrapped.elem.fail_matcher {
ChainBehavior::AndParent(Some(matcher)) => { ChainBehavior::AndParent(Some(matcher)) => {
let local_result = matcher(i); let local_result = matcher(i);
if local_result.is_ok() { if local_result.is_ok() {
@ -78,55 +92,26 @@ impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> {
} }
ChainBehavior::AndParent(None) => {} ChainBehavior::AndParent(None) => {}
ChainBehavior::IgnoreParent(Some(matcher)) => { ChainBehavior::IgnoreParent(Some(matcher)) => {
return matcher(i); 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) => { ChainBehavior::IgnoreParent(None) => {
// TODO: Make this a custom error // TODO: Make this a custom error
return Err(nom::Err::Error(VerboseError::from_error_kind( not(take(0usize))(i)?;
i,
ErrorKind::ManyTill,
)));
} }
}; };
current_node = current_node current_node = current_node.map(|current_head| current_head.next).flatten();
.map(|current_head| current_head.parent)
.flatten();
} }
// TODO: Make this a custom error // TODO: Make this a custom error
return Err(nom::Err::Error(VerboseError::from_error_kind( not(take(0usize))(i)?;
i, unreachable!()
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))
}
}
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);
}
impl<'r, T> std::fmt::Debug for ContextTree<'r, T> { impl<'r, T> std::fmt::Debug for ContextTree<'r, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ContextTree") write!(f, "ContextTree")

View File

@ -29,6 +29,9 @@ use nom::sequence::tuple;
use nom::IResult; use nom::IResult;
use tracing::instrument; use tracing::instrument;
use super::nom_context::ContextTree;
use super::nom_context::OrgModeContextTree;
use super::parser_with_context::parser_with_context;
use super::text_element_parser::paragraph; use super::text_element_parser::paragraph;
pub type Res<T, U> = IResult<T, U, VerboseError<T>>; pub type Res<T, U> = IResult<T, U, VerboseError<T>>;

View File

@ -6,6 +6,7 @@ use crate::parser::parser_with_context::parser_with_context;
use crate::parser::text::paragraph_end; use crate::parser::text::paragraph_end;
use super::nom_context::ContextTree; use super::nom_context::ContextTree;
use super::nom_context::OrgModeContextNode;
use super::nom_context::OrgModeContextTree; use super::nom_context::OrgModeContextTree;
use super::text::bold_end; use super::text::bold_end;
use super::text::bold_start; use super::text::bold_start;
@ -37,7 +38,7 @@ use tracing::instrument;
use tracing::trace; use tracing::trace;
fn context_many_till<'r, I, O, E, F, M, T>( fn context_many_till<'r, I, O, E, F, M, T>(
context: &'r OrgModeContextTree<'r>, context: &'r OrgModeContextNode<'r>,
mut many_matcher: M, mut many_matcher: M,
mut till_matcher: T, mut till_matcher: T,
) -> impl FnMut(I) -> IResult<I, (Vec<O>, F), E> ) -> impl FnMut(I) -> IResult<I, (Vec<O>, F), E>
@ -87,7 +88,7 @@ pub fn document(input: &str) -> Res<&str, Vec<(Vec<TextElement>, &str)>> {
} }
pub fn paragraph<'s, 'r>( pub fn paragraph<'s, 'r>(
context: &'r OrgModeContextTree<'r>, context: &'r OrgModeContextNode<'r>,
i: &'s str, i: &'s str,
) -> Res<&'s str, (Vec<TextElement<'s>>, &'s str)> { ) -> Res<&'s str, (Vec<TextElement<'s>>, &'s str)> {
// Add a not(eof) check because many_till cannot match a zero-length string // Add a not(eof) check because many_till cannot match a zero-length string
@ -100,10 +101,10 @@ pub fn paragraph<'s, 'r>(
} }
fn flat_text_element<'s, 'r>( fn flat_text_element<'s, 'r>(
context: &'r OrgModeContextTree<'r>, context: &'r OrgModeContextNode<'r>,
i: &'s str, i: &'s str,
) -> Res<&'s str, TextElement<'s>> { ) -> Res<&'s str, TextElement<'s>> {
not(|i| context.check_fail_matcher(i))(i)?; not(|i| context.match_fail(i))(i)?;
let bold_matcher = parser_with_context!(flat_bold)(context); let bold_matcher = parser_with_context!(flat_bold)(context);
let link_matcher = parser_with_context!(flat_link)(context); let link_matcher = parser_with_context!(flat_link)(context);
@ -124,7 +125,7 @@ fn recognize_bold_end(input: &str) -> Res<&str, &str> {
recognize(bold_end)(input) recognize(bold_end)(input)
} }
fn flat_bold<'s, 'r>(context: &'r OrgModeContextTree<'r>, i: &'s str) -> Res<&'s str, Bold<'s>> { fn flat_bold<'s, 'r>(context: &'r OrgModeContextNode<'r>, i: &'s str) -> Res<&'s str, Bold<'s>> {
let new_context = context.with_additional_fail_matcher(&recognize_bold_end); let new_context = context.with_additional_fail_matcher(&recognize_bold_end);
let text_element_parser = parser_with_context!(flat_text_element)(&new_context); let text_element_parser = parser_with_context!(flat_text_element)(&new_context);
let (remaining, captured) = recognize(tuple(( let (remaining, captured) = recognize(tuple((
@ -139,7 +140,7 @@ fn recognize_link_end(input: &str) -> Res<&str, &str> {
recognize(link_end)(input) recognize(link_end)(input)
} }
fn flat_link<'s, 'r>(context: &'r OrgModeContextTree<'r>, i: &'s str) -> Res<&'s str, Link<'s>> { fn flat_link<'s, 'r>(context: &'r OrgModeContextNode<'r>, i: &'s str) -> Res<&'s str, Link<'s>> {
let new_context = context.with_additional_fail_matcher(&recognize_link_end); let new_context = context.with_additional_fail_matcher(&recognize_link_end);
let text_element_parser = parser_with_context!(flat_text_element)(&new_context); let text_element_parser = parser_with_context!(flat_text_element)(&new_context);
let (remaining, captured) = recognize(tuple(( let (remaining, captured) = recognize(tuple((