From 6e2ff8b8701762b8553c2c1f194fc6e79cddb073 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 26 Nov 2022 22:36:02 -0500 Subject: [PATCH] Revert "Migrating to the new context tree." This reverts commit c37008df1d41c36780c57054c3d0e0244478c8d5. --- src/parser/mod.rs | 1 + src/parser/new_context.rs | 133 +++++++++++++++++++++++++ src/parser/nom_context.rs | 155 ++++++++++++++---------------- src/parser/text.rs | 3 + src/parser/text_element_parser.rs | 13 +-- 5 files changed, 214 insertions(+), 91 deletions(-) create mode 100644 src/parser/new_context.rs diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 9de44a19..74d94558 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,3 +1,4 @@ +mod new_context; mod nom_context; mod parser_with_context; mod text; diff --git a/src/parser/new_context.rs b/src/parser/new_context.rs new file mode 100644 index 00000000..a6fb06aa --- /dev/null +++ b/src/parser/new_context.rs @@ -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>; +} + +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>, +} + +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> { + Cow::Borrowed(&self.fail_matcher) + } +} + +impl<'r> OrgModeContext<'r> for PreviousElementNode<'r> { + fn get_fail_matcher(&'r self) -> Cow> { + 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") + } +} diff --git a/src/parser/nom_context.rs b/src/parser/nom_context.rs index fb4185e2..71bc9ed1 100644 --- a/src/parser/nom_context.rs +++ b/src/parser/nom_context.rs @@ -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::recognize; -use nom::complete::take; +use nom::error::ContextError; use nom::error::ErrorKind; use nom::error::ParseError; use nom::error::VerboseError; 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>>; -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> { - fn get_fail_matcher(&'r self) -> Cow>; +struct Node<'r, T> { + elem: T, + next: Link<'r, T>, } -struct FailMatcherNode<'r> { - fail_matcher: ChainBehavior<'r>, +pub struct ContextTree<'r, T> { + head: Option>, } -struct PreviousElementNode<'r> { - dummy: &'r str, +impl<'r, T> ContextTree<'r, T> { + 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> { AndParent(Option<&'r Matcher>), IgnoreParent(Option<&'r Matcher>), } -struct Node<'r, T: 'r + ?Sized> { - elem: &'r T, - parent: Link<'r, T>, +pub trait OrgModeContextTree<'r> { + fn with_additional_fail_matcher(&'r self, fail_matcher: &'r Matcher) -> OrgModeContextNode<'r>; + + fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>; } -pub struct ContextTree<'r, T: 'r + ?Sized> { - // Not using Link so the ContextTree can own this node - head: Option>, -} - -impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> { - pub fn new() -> Self { - ContextTree { head: None } +impl<'r> OrgModeContextTree<'r> for OrgModeContextNode<'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)), + }) } - 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), - } - } + // fn with_previous_element(&'r self, dummy: &'r str) -> ContextTree<'r, PreviousElementNode<'r>> { + // self.with_additional_node(PreviousElementNode { + // dummy + // }) + // } - pub fn check_fail_matcher<'s>( - &'r self, - i: &'s str, - ) -> IResult<&'s str, &'s str, VerboseError<&'s str>> { + 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() { - 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() { + let current_node_unwrapped = current_node + .as_ref() + .expect("while loop asserts current_node is some."); + match current_node_unwrapped.elem.fail_matcher { ChainBehavior::AndParent(Some(matcher)) => { let local_result = matcher(i); if local_result.is_ok() { @@ -78,55 +92,26 @@ impl<'r> ContextTree<'r, dyn OrgModeContext<'r>> { } ChainBehavior::AndParent(None) => {} 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) => { // TODO: Make this a custom error - return Err(nom::Err::Error(VerboseError::from_error_kind( - i, - ErrorKind::ManyTill, - ))); + not(take(0usize))(i)?; } }; - current_node = current_node - .map(|current_head| current_head.parent) - .flatten(); + current_node = current_node.map(|current_head| current_head.next).flatten(); } // TODO: Make this a custom error - return Err(nom::Err::Error(VerboseError::from_error_kind( - i, - ErrorKind::ManyTill, - ))); + not(take(0usize))(i)?; + unreachable!() } } -impl<'r> OrgModeContext<'r> for FailMatcherNode<'r> { - fn get_fail_matcher(&'r self) -> Cow> { - Cow::Borrowed(&self.fail_matcher) - } -} - -impl<'r> OrgModeContext<'r> for PreviousElementNode<'r> { - fn get_fail_matcher(&'r self) -> Cow> { - 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") diff --git a/src/parser/text.rs b/src/parser/text.rs index 0b7a9580..8067f1a3 100644 --- a/src/parser/text.rs +++ b/src/parser/text.rs @@ -29,6 +29,9 @@ use nom::sequence::tuple; use nom::IResult; 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; pub type Res = IResult>; diff --git a/src/parser/text_element_parser.rs b/src/parser/text_element_parser.rs index 88f6d4c7..0a2d7ef9 100644 --- a/src/parser/text_element_parser.rs +++ b/src/parser/text_element_parser.rs @@ -6,6 +6,7 @@ use crate::parser::parser_with_context::parser_with_context; use crate::parser::text::paragraph_end; use super::nom_context::ContextTree; +use super::nom_context::OrgModeContextNode; use super::nom_context::OrgModeContextTree; use super::text::bold_end; use super::text::bold_start; @@ -37,7 +38,7 @@ use tracing::instrument; use tracing::trace; fn context_many_till<'r, I, O, E, F, M, T>( - context: &'r OrgModeContextTree<'r>, + context: &'r OrgModeContextNode<'r>, mut many_matcher: M, mut till_matcher: T, ) -> impl FnMut(I) -> IResult, F), E> @@ -87,7 +88,7 @@ pub fn document(input: &str) -> Res<&str, Vec<(Vec, &str)>> { } pub fn paragraph<'s, 'r>( - context: &'r OrgModeContextTree<'r>, + context: &'r OrgModeContextNode<'r>, i: &'s str, ) -> Res<&'s str, (Vec>, &'s str)> { // 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>( - context: &'r OrgModeContextTree<'r>, + context: &'r OrgModeContextNode<'r>, i: &'s str, ) -> 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 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) } -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 text_element_parser = parser_with_context!(flat_text_element)(&new_context); let (remaining, captured) = recognize(tuple(( @@ -139,7 +140,7 @@ fn recognize_link_end(input: &str) -> Res<&str, &str> { 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 text_element_parser = parser_with_context!(flat_text_element)(&new_context); let (remaining, captured) = recognize(tuple((