diff --git a/src/parser/combinator.rs b/src/parser/combinator.rs index dd4d3cc7..dcfabd1f 100644 --- a/src/parser/combinator.rs +++ b/src/parser/combinator.rs @@ -1,40 +1,9 @@ -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::sequence::tuple; use nom::IResult; use nom::InputLength; diff --git a/src/parser/error.rs b/src/parser/error.rs index c45ba142..10b48634 100644 --- a/src/parser/error.rs +++ b/src/parser/error.rs @@ -1,8 +1,5 @@ -use nom::bytes::complete::tag; use nom::error::ErrorKind; use nom::error::ParseError; -use nom::error::VerboseError; -use nom::IResult; #[derive(Debug, PartialEq)] pub enum CustomError { diff --git a/src/parser/nom_context.rs b/src/parser/nom_context.rs index 632dc572..76d1ab23 100644 --- a/src/parser/nom_context.rs +++ b/src/parser/nom_context.rs @@ -1,8 +1,5 @@ use std::rc::Rc; -use nom::bytes::complete::take; -use nom::combinator::not; -use nom::error::VerboseError; use nom::IResult; use super::error::CustomError; diff --git a/src/parser/text.rs b/src/parser/text.rs index fa986506..b1fc2400 100644 --- a/src/parser/text.rs +++ b/src/parser/text.rs @@ -1,17 +1,4 @@ use nom::branch::alt; -/* - -hypothetical link: -fn link = many_till(text_element, link_end) - -but what if you start a bold? -fn bold = many_till(text_element, bold_end) could eat the link_end - -Do I pass along break-conditions? Passing link_end into bold's parser? - -I'll try a very simple language first where asterisks always start/end bold and links are just between [ and ]. Paragraphs will have a blank line between them. - -*/ use nom::bytes::complete::tag; use nom::character::complete::alphanumeric1; use nom::character::complete::line_ending; @@ -19,7 +6,6 @@ use nom::character::complete::space1; use nom::combinator::eof; use nom::combinator::map; use nom::combinator::recognize; -use nom::error::VerboseError; use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; diff --git a/src/parser/text_element_parser.rs b/src/parser/text_element_parser.rs index 72f21db2..fa9d373d 100644 --- a/src/parser/text_element_parser.rs +++ b/src/parser/text_element_parser.rs @@ -10,7 +10,6 @@ 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; @@ -28,32 +27,26 @@ 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::many_till; use nom::sequence::tuple; use nom::IResult; -use nom::InputLength; type UnboundMatcher<'r, 's, I, O, E> = dyn Fn(Context<'r, 's>, I) -> IResult; pub fn document(input: &str) -> Res<&str, Vec> { let initial_context: ContextTree<'_, '_> = ContextTree::new(); let (remaining, tokens) = context_many1(&initial_context, paragraph)(input)?; - let paragraphs = tokens.into_iter().map(|token| { - match token { + let paragraphs = tokens + .into_iter() + .map(|token| match token { Token::TextElement(_) => unreachable!(), Token::Paragraph(paragraph) => paragraph, - } - }).collect(); + }) + .collect(); Ok((remaining, paragraphs)) } @@ -68,6 +61,10 @@ fn can_start_bold<'s, 'r>(context: Context<'r, 's>) -> bool { _preceded_by_whitespace(context) && !_in_section(context, "bold") } +fn can_start_link<'s, 'r>(context: Context<'r, 's>) -> bool { + !_in_section(context, "link") +} + fn _in_section<'s, 'r, 'x>(context: Context<'r, 's>, section_name: &'x str) -> bool { for thing in context.iter() { match thing.get_data() { @@ -128,6 +125,20 @@ pub fn context_bold_start<'s, 'r>( } } +pub fn context_link_start<'s, 'r>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, &'s str> { + if can_start_link(context) { + recognize(link_start)(input) + } else { + // TODO: Make this a specific error instead of just a generic MyError + return Err(nom::Err::Error(CustomError::MyError(MyError( + "Cannot start link", + )))); + } +} + pub fn context_bold_end<'s, 'r>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { let (remaining, actual_match) = recognize(bold_end)(input)?; peek(alt(( @@ -141,6 +152,11 @@ pub fn context_bold_end<'s, 'r>(context: Context<'r, 's>, input: &'s str) -> Res Ok((remaining, actual_match)) } +pub fn context_link_end<'s, 'r>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { + let (remaining, actual_match) = recognize(link_end)(input)?; + Ok((remaining, actual_match)) +} + pub fn paragraph<'s, 'r>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Paragraph<'s>> { // Add a not(eof) check because many_till cannot match a zero-length string not(eof)(i)?; @@ -202,22 +218,16 @@ fn flat_bold<'s, 'r>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Bold< Ok((remaining, ret)) } -fn recognize_link_end<'s, 'r>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { - recognize(link_end)(input) -} - fn flat_link<'s, 'r>(context: Context<'r, 's>, i: &'s str) -> Res<&'s str, Link<'s>> { - // TODO: Link has to be updated to contextual functions like bold was - let nom_context = - context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { - exit_matcher: ChainBehavior::AndParent(Some(&recognize_link_end)), - })); - // let nom_context = context.with_additional_exit_matcher(&recognize_link_end); - let text_element_parser = parser_with_context!(flat_text_element)(&nom_context); - let (remaining, captured) = recognize(tuple(( - link_start, - many_till(text_element_parser, link_end), - )))(i)?; + let link_start = parser_with_context!(context_link_start)(&context); + let nom_context = context + .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + exit_matcher: ChainBehavior::AndParent(Some(&context_link_end)), + })) + .with_additional_node(ContextElement::Context("link")); + let (remaining, captured) = recognize(tuple((link_start, |i| { + context_many_till(&nom_context, flat_text_element, context_link_end)(i) + })))(i)?; let ret = Link { contents: captured }; Ok((remaining, ret)) }