Migrating to the new context tree.
This commit is contained in:
parent
f0de041710
commit
e8b44f27e8
@ -1,4 +1,3 @@
|
||||
mod new_context;
|
||||
mod nom_context;
|
||||
mod parser_with_context;
|
||||
mod text;
|
||||
|
@ -1,133 +0,0 @@
|
||||
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")
|
||||
}
|
||||
}
|
@ -1,89 +1,75 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::take;
|
||||
use nom::combinator::not;
|
||||
use nom::error::ContextError;
|
||||
use nom::combinator::recognize;
|
||||
use nom::complete::take;
|
||||
use nom::error::ErrorKind;
|
||||
use nom::error::ParseError;
|
||||
use nom::error::VerboseError;
|
||||
use nom::IResult;
|
||||
use nom::Parser;
|
||||
use tracing::trace;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::text::bold_end;
|
||||
use super::text::Res;
|
||||
|
||||
type Link<'r, T> = Option<&'r Node<'r, T>>;
|
||||
type Matcher = dyn for<'s> Fn(&'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>>;
|
||||
pub type OrgModeContextNode<'r> = ContextTree<'r, ContextElement<'r>>;
|
||||
type Link<'r, T> = Option<&'r Node<'r, T>>;
|
||||
pub type OrgModeContextTree<'r> = ContextTree<'r, dyn OrgModeContext<'r>>;
|
||||
|
||||
struct Node<'r, T> {
|
||||
elem: T,
|
||||
next: Link<'r, T>,
|
||||
pub trait OrgModeContext<'r> {
|
||||
fn get_fail_matcher(&'r self) -> Cow<ChainBehavior<'r>>;
|
||||
}
|
||||
|
||||
pub struct ContextTree<'r, T> {
|
||||
head: Option<Node<'r, T>>,
|
||||
struct FailMatcherNode<'r> {
|
||||
fail_matcher: ChainBehavior<'r>,
|
||||
}
|
||||
|
||||
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,
|
||||
struct PreviousElementNode<'r> {
|
||||
dummy: &'r str,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ChainBehavior<'r> {
|
||||
AndParent(Option<&'r Matcher>),
|
||||
IgnoreParent(Option<&'r Matcher>),
|
||||
}
|
||||
|
||||
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>>;
|
||||
struct Node<'r, T: 'r + ?Sized> {
|
||||
elem: &'r T,
|
||||
parent: Link<'r, T>,
|
||||
}
|
||||
|
||||
impl<'r> OrgModeContextTree<'r> for OrgModeContextNode<'r> {
|
||||
fn with_additional_fail_matcher(
|
||||
pub 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,
|
||||
fail_matcher: &'r Matcher,
|
||||
) -> ContextTree<'r, ContextElement<'r>> {
|
||||
self.with_additional_node(ContextElement {
|
||||
fail_matcher: ChainBehavior::AndParent(Some(fail_matcher)),
|
||||
})
|
||||
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
|
||||
// })
|
||||
// }
|
||||
|
||||
fn match_fail<'s>(&'r self, i: &'s str) -> IResult<&'s str, &'s str, VerboseError<&'s str>> {
|
||||
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
|
||||
.as_ref()
|
||||
.expect("while loop asserts current_node is some.");
|
||||
match current_node_unwrapped.elem.fail_matcher {
|
||||
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() {
|
||||
@ -92,26 +78,55 @@ impl<'r> OrgModeContextTree<'r> for OrgModeContextNode<'r> {
|
||||
}
|
||||
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)?;
|
||||
return matcher(i);
|
||||
}
|
||||
ChainBehavior::IgnoreParent(None) => {
|
||||
// TODO: Make this a custom error
|
||||
not(take(0usize))(i)?;
|
||||
return Err(nom::Err::Error(VerboseError::from_error_kind(
|
||||
i,
|
||||
ErrorKind::ManyTill,
|
||||
)));
|
||||
}
|
||||
};
|
||||
current_node = current_node.map(|current_head| current_head.next).flatten();
|
||||
current_node = current_node
|
||||
.map(|current_head| current_head.parent)
|
||||
.flatten();
|
||||
}
|
||||
// TODO: Make this a custom error
|
||||
not(take(0usize))(i)?;
|
||||
unreachable!()
|
||||
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")
|
||||
|
@ -29,9 +29,6 @@ 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<T, U> = IResult<T, U, VerboseError<T>>;
|
||||
|
@ -6,7 +6,6 @@ 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;
|
||||
@ -38,7 +37,7 @@ use tracing::instrument;
|
||||
use tracing::trace;
|
||||
|
||||
fn context_many_till<'r, I, O, E, F, M, T>(
|
||||
context: &'r OrgModeContextNode<'r>,
|
||||
context: &'r OrgModeContextTree<'r>,
|
||||
mut many_matcher: M,
|
||||
mut till_matcher: T,
|
||||
) -> impl FnMut(I) -> IResult<I, (Vec<O>, F), E>
|
||||
@ -88,7 +87,7 @@ pub fn document(input: &str) -> Res<&str, Vec<(Vec<TextElement>, &str)>> {
|
||||
}
|
||||
|
||||
pub fn paragraph<'s, 'r>(
|
||||
context: &'r OrgModeContextNode<'r>,
|
||||
context: &'r OrgModeContextTree<'r>,
|
||||
i: &'s str,
|
||||
) -> Res<&'s str, (Vec<TextElement<'s>>, &'s str)> {
|
||||
// Add a not(eof) check because many_till cannot match a zero-length string
|
||||
@ -101,10 +100,10 @@ pub fn paragraph<'s, 'r>(
|
||||
}
|
||||
|
||||
fn flat_text_element<'s, 'r>(
|
||||
context: &'r OrgModeContextNode<'r>,
|
||||
context: &'r OrgModeContextTree<'r>,
|
||||
i: &'s str,
|
||||
) -> Res<&'s str, TextElement<'s>> {
|
||||
not(|i| context.match_fail(i))(i)?;
|
||||
not(|i| context.check_fail_matcher(i))(i)?;
|
||||
|
||||
let bold_matcher = parser_with_context!(flat_bold)(context);
|
||||
let link_matcher = parser_with_context!(flat_link)(context);
|
||||
@ -125,7 +124,7 @@ fn recognize_bold_end(input: &str) -> Res<&str, &str> {
|
||||
recognize(bold_end)(input)
|
||||
}
|
||||
|
||||
fn flat_bold<'s, 'r>(context: &'r OrgModeContextNode<'r>, i: &'s str) -> Res<&'s str, Bold<'s>> {
|
||||
fn flat_bold<'s, 'r>(context: &'r OrgModeContextTree<'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((
|
||||
@ -140,7 +139,7 @@ fn recognize_link_end(input: &str) -> Res<&str, &str> {
|
||||
recognize(link_end)(input)
|
||||
}
|
||||
|
||||
fn flat_link<'s, 'r>(context: &'r OrgModeContextNode<'r>, i: &'s str) -> Res<&'s str, Link<'s>> {
|
||||
fn flat_link<'s, 'r>(context: &'r OrgModeContextTree<'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((
|
||||
|
Loading…
x
Reference in New Issue
Block a user