diff --git a/src/parser/document.rs b/src/parser/document.rs index 9020903..6e202f5 100644 --- a/src/parser/document.rs +++ b/src/parser/document.rs @@ -124,7 +124,7 @@ fn zeroth_section<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s s let without_consuming_whitespace_context = parser_context.with_additional_node(ContextElement::ConsumeTrailingWhitespace(false)); - let element_matcher = parser_with_context!(element)(&parser_context); + let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, comment_and_property_drawer_element) = opt(tuple(( @@ -166,7 +166,7 @@ fn section<'r, 's>(context: Context<'r, 's>, mut input: &'s str) -> Res<&'s str, class: ExitClass::Document, exit_matcher: §ion_end, })); - let element_matcher = parser_with_context!(element)(&parser_context); + let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); // TODO: Match whatever a planning is. let (mut remaining, (planning_element, property_drawer_element)) = tuple(( diff --git a/src/parser/drawer.rs b/src/parser/drawer.rs index e6e0fe0..9c93a94 100644 --- a/src/parser/drawer.rs +++ b/src/parser/drawer.rs @@ -54,7 +54,7 @@ pub fn drawer<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, exit_matcher: &drawer_end, })); - let element_matcher = parser_with_context!(element)(&parser_context); + let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, children) = match consumed(many_till(blank_line, exit_matcher))(remaining) { Ok((remaining, (whitespace, (_children, _exit_contents)))) => ( diff --git a/src/parser/dynamic_block.rs b/src/parser/dynamic_block.rs index 5d6e156..d523920 100644 --- a/src/parser/dynamic_block.rs +++ b/src/parser/dynamic_block.rs @@ -59,7 +59,7 @@ pub fn dynamic_block<'r, 's>( Some((_ws, parameters)) => Some(parameters), None => None, }; - let element_matcher = parser_with_context!(element)(&parser_context); + let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, children) = match consumed(many_till(blank_line, exit_matcher))(remaining) { Ok((remaining, (whitespace, (_children, _exit_contents)))) => ( diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 7ae672b..640ebcc 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -21,94 +21,76 @@ use super::util::get_consumed; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; use super::Context; +use crate::error::CustomError; +use crate::error::MyError; use crate::error::Res; use crate::parser::parser_with_context::parser_with_context; use crate::parser::table::org_mode_table; use nom::branch::alt; +use nom::combinator::cond; use nom::combinator::map; +use nom::combinator::verify; use nom::multi::many0; -#[tracing::instrument(ret, level = "debug")] -pub fn element<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Element<'s>> { - let non_paragraph_matcher = parser_with_context!(non_paragraph_element)(context); - let paragraph_matcher = parser_with_context!(paragraph_element)(context); +pub fn element( + can_be_paragraph: bool, +) -> impl for<'r, 's> Fn(Context<'r, 's>, &'s str) -> Res<&'s str, Element<'s>> { + move |context: Context, input: &str| { + let plain_list_matcher = parser_with_context!(plain_list)(context); + let greater_block_matcher = parser_with_context!(greater_block)(context); + let dynamic_block_matcher = parser_with_context!(dynamic_block)(context); + let footnote_definition_matcher = parser_with_context!(footnote_definition)(context); + let comment_matcher = parser_with_context!(comment)(context); + let drawer_matcher = parser_with_context!(drawer)(context); + let table_matcher = parser_with_context!(org_mode_table)(context); + let verse_block_matcher = parser_with_context!(verse_block)(context); + let comment_block_matcher = parser_with_context!(comment_block)(context); + let example_block_matcher = parser_with_context!(example_block)(context); + let export_block_matcher = parser_with_context!(export_block)(context); + let src_block_matcher = parser_with_context!(src_block)(context); + let clock_matcher = parser_with_context!(clock)(context); + let diary_sexp_matcher = parser_with_context!(diary_sexp)(context); + let fixed_width_area_matcher = parser_with_context!(fixed_width_area)(context); + let horizontal_rule_matcher = parser_with_context!(horizontal_rule)(context); + let keyword_matcher = parser_with_context!(keyword)(context); + let paragraph_matcher = parser_with_context!(paragraph)(context); + let (remaining, mut affiliated_keywords) = many0(keyword_matcher)(input)?; + let (remaining, mut element) = match alt(( + map(plain_list_matcher, Element::PlainList), + map(greater_block_matcher, Element::GreaterBlock), + map(dynamic_block_matcher, Element::DynamicBlock), + map(footnote_definition_matcher, Element::FootnoteDefinition), + map(comment_matcher, Element::Comment), + map(drawer_matcher, Element::Drawer), + map(table_matcher, Element::Table), + map(verse_block_matcher, Element::VerseBlock), + map(comment_block_matcher, Element::CommentBlock), + map(example_block_matcher, Element::ExampleBlock), + map(export_block_matcher, Element::ExportBlock), + map(src_block_matcher, Element::SrcBlock), + map(clock_matcher, Element::Clock), + map(diary_sexp_matcher, Element::DiarySexp), + map(fixed_width_area_matcher, Element::FixedWidthArea), + map(horizontal_rule_matcher, Element::HorizontalRule), + map( + verify(paragraph_matcher, |_p| can_be_paragraph), + Element::Paragraph, + ), + ))(remaining) + { + the_ok @ Ok(_) => the_ok, + Err(_) => { + affiliated_keywords.clear(); + map(keyword_matcher, Element::Keyword)(input) + } + }?; - alt((non_paragraph_matcher, paragraph_matcher))(input) -} - -#[tracing::instrument(ret, level = "debug")] -pub fn paragraph_element<'r, 's>( - context: Context<'r, 's>, - input: &'s str, -) -> Res<&'s str, Element<'s>> { - let paragraph_matcher = parser_with_context!(paragraph)(context); - let keyword_matcher = parser_with_context!(keyword)(context); - let (remaining, _affiliated_keywords) = many0(keyword_matcher)(input)?; - let (remaining, mut element) = map(paragraph_matcher, Element::Paragraph)(remaining)?; - - let (remaining, _trailing_ws) = - maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; - - let source = get_consumed(input, remaining); - element.set_source(source); - - Ok((remaining, element)) -} - -#[tracing::instrument(ret, level = "debug")] -pub fn non_paragraph_element<'r, 's>( - context: Context<'r, 's>, - input: &'s str, -) -> Res<&'s str, Element<'s>> { - let plain_list_matcher = parser_with_context!(plain_list)(context); - let greater_block_matcher = parser_with_context!(greater_block)(context); - let dynamic_block_matcher = parser_with_context!(dynamic_block)(context); - let footnote_definition_matcher = parser_with_context!(footnote_definition)(context); - let comment_matcher = parser_with_context!(comment)(context); - let drawer_matcher = parser_with_context!(drawer)(context); - let table_matcher = parser_with_context!(org_mode_table)(context); - let verse_block_matcher = parser_with_context!(verse_block)(context); - let comment_block_matcher = parser_with_context!(comment_block)(context); - let example_block_matcher = parser_with_context!(example_block)(context); - let export_block_matcher = parser_with_context!(export_block)(context); - let src_block_matcher = parser_with_context!(src_block)(context); - let clock_matcher = parser_with_context!(clock)(context); - let diary_sexp_matcher = parser_with_context!(diary_sexp)(context); - let fixed_width_area_matcher = parser_with_context!(fixed_width_area)(context); - let horizontal_rule_matcher = parser_with_context!(horizontal_rule)(context); - let keyword_matcher = parser_with_context!(keyword)(context); - let (remaining, mut affiliated_keywords) = many0(keyword_matcher)(input)?; - let (remaining, mut element) = match alt(( - map(plain_list_matcher, Element::PlainList), - map(greater_block_matcher, Element::GreaterBlock), - map(dynamic_block_matcher, Element::DynamicBlock), - map(footnote_definition_matcher, Element::FootnoteDefinition), - map(comment_matcher, Element::Comment), - map(drawer_matcher, Element::Drawer), - map(table_matcher, Element::Table), - map(verse_block_matcher, Element::VerseBlock), - map(comment_block_matcher, Element::CommentBlock), - map(example_block_matcher, Element::ExampleBlock), - map(export_block_matcher, Element::ExportBlock), - map(src_block_matcher, Element::SrcBlock), - map(clock_matcher, Element::Clock), - map(diary_sexp_matcher, Element::DiarySexp), - map(fixed_width_area_matcher, Element::FixedWidthArea), - map(horizontal_rule_matcher, Element::HorizontalRule), - ))(remaining) - { - the_ok @ Ok(_) => the_ok, - Err(_) => { - affiliated_keywords.clear(); - map(keyword_matcher, Element::Keyword)(input) - } - }?; - - let (remaining, _trailing_ws) = - maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; - - let source = get_consumed(input, remaining); - element.set_source(source); - - Ok((remaining, element)) + let (remaining, _trailing_ws) = + maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; + + let source = get_consumed(input, remaining); + element.set_source(source); + + Ok((remaining, element)) + } } diff --git a/src/parser/footnote_definition.rs b/src/parser/footnote_definition.rs index ffc4c52..00f1077 100644 --- a/src/parser/footnote_definition.rs +++ b/src/parser/footnote_definition.rs @@ -50,7 +50,7 @@ pub fn footnote_definition<'r, 's>( exit_matcher: &footnote_definition_end, })); // TODO: The problem is we are not accounting for trailing whitespace like we do in section. Maybe it would be easier if we passed down whether or not to parse trailing whitespace into the element matcher similar to how tag takes in parameters. - let element_matcher = parser_with_context!(element)(&parser_context); + let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, (children, _exit_contents)) = many_till(element_matcher, exit_matcher)(remaining)?; @@ -124,7 +124,7 @@ line footnote."; let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let footnote_definition_matcher = parser_with_context!(element)(&document_context); + let footnote_definition_matcher = parser_with_context!(element(true))(&document_context); let (remaining, first_footnote_definition) = footnote_definition_matcher(input).expect("Parse first footnote_definition"); let (remaining, second_footnote_definition) = @@ -155,7 +155,7 @@ not in the footnote."; let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let footnote_definition_matcher = parser_with_context!(element)(&document_context); + let footnote_definition_matcher = parser_with_context!(element(true))(&document_context); let (remaining, first_footnote_definition) = footnote_definition_matcher(input).expect("Parse first footnote_definition"); assert_eq!(remaining, "not in the footnote."); diff --git a/src/parser/greater_block.rs b/src/parser/greater_block.rs index 7855a2c..8ca1fe1 100644 --- a/src/parser/greater_block.rs +++ b/src/parser/greater_block.rs @@ -69,7 +69,7 @@ pub fn greater_block<'r, 's>( None => None, }; - let element_matcher = parser_with_context!(element)(&parser_context); + let element_matcher = parser_with_context!(element(true))(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); // Check for a completely empty block let (remaining, children) = match consumed(many_till(blank_line, exit_matcher))(remaining) { diff --git a/src/parser/paragraph.rs b/src/parser/paragraph.rs index c0deadb..1bf3c41 100644 --- a/src/parser/paragraph.rs +++ b/src/parser/paragraph.rs @@ -16,7 +16,6 @@ use crate::parser::util::exit_matcher_parser; use crate::parser::util::start_of_line; -use super::element_parser::non_paragraph_element; use super::lesser_element::Paragraph; use super::util::blank_line; use super::util::get_consumed; @@ -46,7 +45,7 @@ pub fn paragraph<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s st #[tracing::instrument(ret, level = "debug")] fn paragraph_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { - let non_paragraph_element_matcher = parser_with_context!(non_paragraph_element)(context); + let non_paragraph_element_matcher = parser_with_context!(element(false))(context); let start_of_line_matcher = parser_with_context!(start_of_line)(&context); alt(( recognize(tuple((start_of_line_matcher, many1(blank_line)))), @@ -57,7 +56,7 @@ fn paragraph_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s st #[cfg(test)] mod tests { - use crate::parser::element_parser::paragraph_element; + use crate::parser::element_parser::element; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ContextTree; use crate::parser::parser_with_context::parser_with_context; @@ -71,7 +70,7 @@ mod tests { let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let paragraph_matcher = parser_with_context!(paragraph_element)(&document_context); + let paragraph_matcher = parser_with_context!(element(true))(&document_context); let (remaining, first_paragraph) = paragraph_matcher(input).expect("Parse first paragraph"); let (remaining, second_paragraph) = paragraph_matcher(remaining).expect("Parse second paragraph."); diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 4e5704f..436208d 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -161,8 +161,8 @@ pub fn plain_list_item<'r, 's>( exit_matcher: &plain_list_item_end, })); - let with_consume_matcher = parser_with_context!(element)(&with_consume_context); - let without_consume_matcher = parser_with_context!(element)(&without_consume_context); + let with_consume_matcher = parser_with_context!(element(true))(&with_consume_context); + let without_consume_matcher = parser_with_context!(element(true))(&without_consume_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&with_consume_context); let (remaining, bull) = verify(bullet, |bull: &str| bull != "*" || indent_level > 0)(remaining)?; @@ -370,7 +370,7 @@ mod tests { let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let plain_list_matcher = parser_with_context!(element)(&document_context); + let plain_list_matcher = parser_with_context!(element(true))(&document_context); let (remaining, result) = plain_list_matcher(input).expect("Should parse the plain list successfully."); assert_eq!(remaining, " ipsum\n"); @@ -396,7 +396,7 @@ baz"#; let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let plain_list_matcher = parser_with_context!(element)(&document_context); + let plain_list_matcher = parser_with_context!(element(true))(&document_context); let (remaining, result) = plain_list_matcher(input).expect("Should parse the plain list successfully."); assert_eq!(remaining, "baz"); @@ -427,7 +427,8 @@ dolar"#; let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let plain_list_matcher = parser_with_context!(element)(&document_context); + let element_matcher = element(true); + let plain_list_matcher = parser_with_context!(element_matcher)(&document_context); let (remaining, result) = plain_list_matcher(input).expect("Should parse the plain list successfully."); assert_eq!(remaining, "dolar");