use crate::parser::parser_with_context::parser_with_context; use crate::parser::text::paragraph_end; use super::error::CustomError; use super::error::MyError; use super::nom_context::ChainBehavior; use super::nom_context::ContextElement; use super::nom_context::ContextTree; use super::nom_context::ExitMatcherNode; use super::nom_context::PreviousElementNode; use super::text::bold_end; use super::text::bold_start; use super::text::line_break; use super::text::link_end; use super::text::link_start; use super::text::space; use super::text::span; use super::text::symbol; use super::text::Bold; use super::text::Link; use super::text::Res; use super::text::TextElement; use super::token::Token; use super::Context; use nom::branch::alt; use nom::bytes::complete::tag; use nom::bytes::complete::take; use nom::combinator::cond; use nom::combinator::eof; use nom::combinator::map; use nom::combinator::not; use nom::combinator::peek; use nom::combinator::recognize; use nom::error::ErrorKind; use nom::error::ParseError; use nom::error::VerboseError; use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; use nom::IResult; use nom::InputLength; pub fn context_many_till<'r, 's, I, O, E, F, M, T>( context: Context<'r, 's>, mut many_matcher: M, mut till_matcher: T, ) -> impl FnMut(I) -> IResult>, F), E> + 'r where I: Clone + InputLength, E: ParseError, M: for<'x> Fn(Context<'x, 's>, I) -> IResult + 'r, T: for<'x> Fn(Context<'x, 's>, I) -> IResult + 'r, O: Into>, { move |mut i: I| { // TODO: Can I eliminate the clone? let mut current_context = context.clone(); // Despite the clone, the Rc should still point to the same value, otherwise we'll get stuck in an endless loop. assert!(current_context.ptr_eq(context)); loop { let len = i.input_len(); match till_matcher(¤t_context, i.clone()) { Ok((remaining, finish)) => { let mut ret = Vec::new(); while !current_context.ptr_eq(context) { let (context_element, next_context) = current_context.pop_front(); let context_element = context_element.expect("We only pop off context elements created in this function, so they are all Some()"); current_context = next_context; match context_element { ContextElement::ExitMatcherNode(_) => {} ContextElement::StartOfParagraph => {} ContextElement::Context(_) => {} ContextElement::PreviousElementNode(PreviousElementNode { element: token, }) => { ret.push(token); } }; } ret.reverse(); return Ok((remaining, (ret, finish))); } Err(nom::Err::Error(_)) => { match many_matcher(¤t_context, i.clone()) { Err(nom::Err::Error(err)) => { return Err(nom::Err::Error(E::append(i, ErrorKind::ManyTill, err))) } Err(e) => return Err(e), Ok((remaining, many_elem)) => { // infinite loop check: the parser must always consume if remaining.input_len() == len { return Err(nom::Err::Error(E::from_error_kind( remaining, ErrorKind::ManyTill, ))); } current_context = current_context.with_additional_node( ContextElement::PreviousElementNode(PreviousElementNode { element: many_elem.into(), }), ); i = remaining; } } } Err(e) => return Err(e), }; } } }