From 176e37874ec66e133cd45f7c44061ed7c254a805 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 15:25:26 -0400 Subject: [PATCH 01/15] Remove the parser to parse affiliated keywords as regular keywords. --- src/parser/element_parser.rs | 20 -------------------- src/parser/keyword.rs | 16 ---------------- 2 files changed, 36 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 12629242..6288efb3 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -21,7 +21,6 @@ use super::footnote_definition::footnote_definition; use super::greater_block::greater_block; use super::horizontal_rule::horizontal_rule; use super::keyword::affiliated_keyword; -use super::keyword::affiliated_keyword_as_regular_keyword; use super::keyword::keyword; use super::latex_environment::latex_environment; use super::lesser_block::comment_block; @@ -129,25 +128,6 @@ fn _element<'b, 'g, 'r, 's>( } } - if maybe_element.is_none() { - #[cfg(feature = "tracing")] - let span = span!( - tracing::Level::DEBUG, - "Affiliated keyword as regular keyword." - ); - #[cfg(feature = "tracing")] - let _enter = span.enter(); - - let (remain, kw) = opt(map( - parser_with_context!(affiliated_keyword_as_regular_keyword)(context), - Element::Keyword, - ))(remaining)?; - if kw.is_some() { - maybe_element = kw; - remaining = remain; - } - } - if maybe_element.is_none() && can_be_paragraph { #[cfg(feature = "tracing")] let span = span!( diff --git a/src/parser/keyword.rs b/src/parser/keyword.rs index cb6ae152..4e5eb1b9 100644 --- a/src/parser/keyword.rs +++ b/src/parser/keyword.rs @@ -109,22 +109,6 @@ pub(crate) fn keyword<'b, 'g, 'r, 's>( Ok((remaining, kw)) } -#[cfg_attr( - feature = "tracing", - tracing::instrument(ret, level = "debug", skip(context)) -)] -pub(crate) fn affiliated_keyword_as_regular_keyword<'b, 'g, 'r, 's>( - context: RefContext<'b, 'g, 'r, 's>, - input: OrgSource<'s>, -) -> Res, Keyword<'s>> { - let (remaining, mut kw) = affiliated_keyword(input)?; - let (remaining, _trailing_ws) = - maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; - let source = get_consumed(input, remaining); - kw.source = Into::<&str>::into(source); - Ok((remaining, kw)) -} - #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn affiliated_keyword<'s>(input: OrgSource<'s>) -> Res, Keyword<'s>> { filtered_keyword(affiliated_key)(input) From a6f36ba6795dd759b7d1a73205408ddc372bac9c Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 15:47:06 -0400 Subject: [PATCH 02/15] Create a template for new element functions that will take in the affiliated keywords instead of re-parsing them multiple times. --- src/parser/affiliated_keyword.rs | 11 +++++++---- src/parser/element_parser.rs | 3 +++ src/parser/macros.rs | 1 + src/parser/mod.rs | 1 + src/parser/plain_list.rs | 17 +++++++++++++++++ 5 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/parser/macros.rs diff --git a/src/parser/affiliated_keyword.rs b/src/parser/affiliated_keyword.rs index 498033f8..92b59fce 100644 --- a/src/parser/affiliated_keyword.rs +++ b/src/parser/affiliated_keyword.rs @@ -25,12 +25,15 @@ use crate::types::AffiliatedKeywordValue; use crate::types::AffiliatedKeywords; use crate::types::Keyword; -pub(crate) fn parse_affiliated_keywords<'g, 's>( +pub(crate) fn parse_affiliated_keywords<'g, 's, AK>( global_settings: &'g GlobalSettings<'g, 's>, - input: Vec>, -) -> AffiliatedKeywords<'s> { + input: AK, +) -> AffiliatedKeywords<'s> +where + AK: IntoIterator>, +{ let mut ret = BTreeMap::new(); - for kw in input.into_iter() { + for kw in input { let translated_name = translate_name(global_settings, kw.key); if is_single_string_keyword(global_settings, translated_name.as_str()) { ret.insert( diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 6288efb3..0be05041 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -2,6 +2,7 @@ use nom::branch::alt; use nom::combinator::map; use nom::combinator::opt; use nom::combinator::peek; +use nom::multi::many0; use nom::sequence::tuple; #[cfg(feature = "tracing")] use tracing::span; @@ -59,6 +60,8 @@ fn _element<'b, 'g, 'r, 's>( input: OrgSource<'s>, can_be_paragraph: bool, ) -> Res, Element<'s>> { + let (post_affiliated_keywords_input, affiliated_keywords) = many0(affiliated_keyword)(input)?; + 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); diff --git a/src/parser/macros.rs b/src/parser/macros.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/parser/macros.rs @@ -0,0 +1 @@ + diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c9c2e6e3..dff7f192 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -27,6 +27,7 @@ mod latex_environment; mod latex_fragment; mod lesser_block; mod line_break; +mod macros; mod object_parser; mod org_macro; mod org_source; diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 3035f6bc..adb0dc3e 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -43,6 +43,7 @@ use crate::parser::util::org_space; use crate::parser::util::start_of_line; use crate::types::CheckboxType; use crate::types::IndentationLevel; +use crate::types::Keyword; use crate::types::Object; use crate::types::PlainList; use crate::types::PlainListItem; @@ -79,6 +80,22 @@ pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>( )))); } +#[cfg_attr( + feature = "tracing", + tracing::instrument(ret, level = "debug", skip(context)) +)] +pub(crate) fn new_plain_list<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, + context: RefContext<'b, 'g, 'r, 's>, + input: OrgSource<'s>, +) -> Res, PlainList<'s>> +where + AK: Iterator>, +{ + todo!() +} + #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) From 6ca4dc8ffcb3d64ede645053a690383ea7c5ed6b Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:06:59 -0400 Subject: [PATCH 03/15] Add a macro for calling parsers that take in the affiliated keywords. --- src/parser/element_parser.rs | 15 +++++++++++++++ src/parser/macros.rs | 24 ++++++++++++++++++++++++ src/parser/plain_list.rs | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 0be05041..ff9a8c26 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -32,6 +32,7 @@ use super::lesser_block::verse_block; use super::org_source::OrgSource; use super::paragraph::paragraph; use super::plain_list::detect_plain_list; +use super::plain_list::new_plain_list; use super::plain_list::plain_list; use super::table::detect_table; use crate::context::parser_with_context; @@ -39,6 +40,7 @@ use crate::context::RefContext; use crate::error::CustomError; use crate::error::MyError; use crate::error::Res; +use crate::parser::macros::ak_element; use crate::parser::table::org_mode_table; use crate::types::Element; @@ -62,6 +64,17 @@ fn _element<'b, 'g, 'r, 's>( ) -> Res, Element<'s>> { let (post_affiliated_keywords_input, affiliated_keywords) = many0(affiliated_keyword)(input)?; + let mut affiliated_keywords = affiliated_keywords.into_iter(); + + ak_element!( + new_plain_list, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::PlainList + ); + 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); @@ -131,6 +144,8 @@ fn _element<'b, 'g, 'r, 's>( } } + // TODO: These two paragraphs need to be revisited using the affiliated keywords parsed above. + if maybe_element.is_none() && can_be_paragraph { #[cfg(feature = "tracing")] let span = span!( diff --git a/src/parser/macros.rs b/src/parser/macros.rs index 8b137891..86659baf 100644 --- a/src/parser/macros.rs +++ b/src/parser/macros.rs @@ -1 +1,25 @@ +/// Parse an element that has affiliated keywords. +macro_rules! ak_element { + ($parser:ident, $affiliated_keywords:expr, $post_affiliated_keywords_input: expr, $context: expr, $input: expr, $wrapper: expr) => { + if let Ok((remaining, ele)) = $parser( + $affiliated_keywords, + $post_affiliated_keywords_input, + $context, + $input, + ) { + return Ok((remaining, $wrapper(ele))); + } + }; + ($parser:ident, $affiliated_keywords:expr, $post_affiliated_keywords_input: expr, $context: expr, $input: expr) => { + if let Ok((remaining, ele)) = $parser( + $affiliated_keywords, + $post_affiliated_keywords_input, + $context, + $input, + ) { + return Ok((remaining, ele)); + } + }; +} +pub(crate) use ak_element; diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index adb0dc3e..18f1ae76 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -91,7 +91,7 @@ pub(crate) fn new_plain_list<'b, 'g, 'r, 's, AK>( input: OrgSource<'s>, ) -> Res, PlainList<'s>> where - AK: Iterator>, + AK: IntoIterator>, { todo!() } From 8654cf5507a90bb246d08d722f22f9276fc41851 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:09:35 -0400 Subject: [PATCH 04/15] Fully port over the first parser. --- src/parser/element_parser.rs | 5 +---- src/parser/plain_list.rs | 15 +-------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index ff9a8c26..59edad62 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -32,7 +32,6 @@ use super::lesser_block::verse_block; use super::org_source::OrgSource; use super::paragraph::paragraph; use super::plain_list::detect_plain_list; -use super::plain_list::new_plain_list; use super::plain_list::plain_list; use super::table::detect_table; use crate::context::parser_with_context; @@ -67,7 +66,7 @@ fn _element<'b, 'g, 'r, 's>( let mut affiliated_keywords = affiliated_keywords.into_iter(); ak_element!( - new_plain_list, + plain_list, &mut affiliated_keywords, post_affiliated_keywords_input, context, @@ -75,7 +74,6 @@ fn _element<'b, 'g, 'r, 's>( Element::PlainList ); - 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); @@ -103,7 +101,6 @@ fn _element<'b, 'g, 'r, 's>( let _enter = span.enter(); opt(alt(( - map(plain_list_matcher, Element::PlainList), greater_block_matcher, map(dynamic_block_matcher, Element::DynamicBlock), map(footnote_definition_matcher, Element::FootnoteDefinition), diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 18f1ae76..d404e961 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -84,7 +84,7 @@ pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn new_plain_list<'b, 'g, 'r, 's, AK>( +pub(crate) fn plain_list<'b, 'g, 'r, 's, AK>( affiliated_keywords: AK, remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, @@ -93,19 +93,6 @@ pub(crate) fn new_plain_list<'b, 'g, 'r, 's, AK>( where AK: IntoIterator>, { - todo!() -} - -#[cfg_attr( - feature = "tracing", - tracing::instrument(ret, level = "debug", skip(context)) -)] -pub(crate) fn plain_list<'b, 'g, 'r, 's>( - context: RefContext<'b, 'g, 'r, 's>, - input: OrgSource<'s>, -) -> Res, PlainList<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; - let contexts = [ ContextElement::Context("plain list"), ContextElement::ConsumeTrailingWhitespace(true), From 5136880532a043d2877d521909e6127efca7ed24 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:14:23 -0400 Subject: [PATCH 05/15] Fix tests. --- src/parser/plain_list.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index d404e961..f3148f24 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -584,8 +584,8 @@ mod tests { let global_settings = GlobalSettings::default(); let initial_context = ContextElement::document_context(); let initial_context = Context::new(&global_settings, List::new(&initial_context)); - let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); - let (remaining, result) = plain_list_matcher(input).unwrap(); + let (remaining, result) = + plain_list(std::iter::empty(), input, &initial_context, input).unwrap(); assert_eq!(Into::<&str>::into(remaining), ""); assert_eq!(result.get_standard_properties().get_source(), "1."); } @@ -596,8 +596,8 @@ mod tests { let global_settings = GlobalSettings::default(); let initial_context = ContextElement::document_context(); let initial_context = Context::new(&global_settings, List::new(&initial_context)); - let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); - let (remaining, result) = plain_list_matcher(input).unwrap(); + let (remaining, result) = + plain_list(std::iter::empty(), input, &initial_context, input).unwrap(); assert_eq!(Into::<&str>::into(remaining), ""); assert_eq!(result.get_standard_properties().get_source(), "1. foo"); } @@ -609,8 +609,7 @@ mod tests { let global_settings = GlobalSettings::default(); let initial_context = ContextElement::document_context(); let initial_context = Context::new(&global_settings, List::new(&initial_context)); - let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); - let result = plain_list_matcher(input); + let result = plain_list(std::iter::empty(), input, &initial_context, input); assert!(result.is_err()); } @@ -621,8 +620,7 @@ mod tests { let global_settings = GlobalSettings::default(); let initial_context = ContextElement::document_context(); let initial_context = Context::new(&global_settings, List::new(&initial_context)); - let plain_list_matcher = parser_with_context!(plain_list)(&initial_context); - let result = plain_list_matcher(input); + let result = plain_list(std::iter::empty(), input, &initial_context, input); assert!(result.is_ok()); } From 59448a4f2c7f4736c504d599d7d8634c9e3fa0be Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:27:57 -0400 Subject: [PATCH 06/15] Port greater blocker over to ak_element!(). --- src/parser/element_parser.rs | 10 ++++++-- src/parser/greater_block.rs | 50 +++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 59edad62..ef67395f 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -74,7 +74,14 @@ fn _element<'b, 'g, 'r, 's>( Element::PlainList ); - let greater_block_matcher = parser_with_context!(greater_block)(context); + ak_element!( + greater_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input + ); + 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); @@ -101,7 +108,6 @@ fn _element<'b, 'g, 'r, 's>( let _enter = span.enter(); opt(alt(( - greater_block_matcher, map(dynamic_block_matcher, Element::DynamicBlock), map(footnote_definition_matcher, Element::FootnoteDefinition), map(comment_matcher, Element::Comment), diff --git a/src/parser/greater_block.rs b/src/parser/greater_block.rs index 17ba0723..daf59dfc 100644 --- a/src/parser/greater_block.rs +++ b/src/parser/greater_block.rs @@ -18,7 +18,6 @@ use nom::sequence::preceded; use nom::sequence::tuple; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::in_section; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; @@ -48,12 +47,15 @@ use crate::types::SpecialBlock; feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn greater_block<'b, 'g, 'r, 's>( - context: RefContext<'b, 'g, 'r, 's>, +pub(crate) fn greater_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, input: OrgSource<'s>, -) -> Res, Element<'s>> { - let pre_affiliated_keywords_input = input; - let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; + context: RefContext<'b, 'g, 'r, 's>, + pre_affiliated_keywords_input: OrgSource<'s>, +) -> Res, Element<'s>> +where + AK: IntoIterator>, +{ start_of_line(input)?; let (remaining, _leading_whitespace) = space0(input)?; let (remaining, (_begin, name)) = tuple(( @@ -93,12 +95,15 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -fn center_block<'b, 'g, 'r, 's>( +fn center_block<'b, 'g, 'r, 's, AK>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, pre_affiliated_keywords_input: OrgSource<'s>, - affiliated_keywords: Vec>, -) -> Res, Element<'s>> { + affiliated_keywords: AK, +) -> Res, Element<'s>> +where + AK: IntoIterator>, +{ let (remaining, (source, children)) = greater_block_body( context, input, @@ -123,12 +128,15 @@ fn center_block<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -fn quote_block<'b, 'g, 'r, 's>( +fn quote_block<'b, 'g, 'r, 's, AK>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, pre_affiliated_keywords_input: OrgSource<'s>, - affiliated_keywords: Vec>, -) -> Res, Element<'s>> { + affiliated_keywords: AK, +) -> Res, Element<'s>> +where + AK: IntoIterator>, +{ let (remaining, (source, children)) = greater_block_body( context, input, @@ -149,15 +157,18 @@ fn quote_block<'b, 'g, 'r, 's>( )) } -fn special_block<'s>( +fn special_block<'s, AK>( name: &'s str, ) -> impl for<'b, 'g, 'r> Fn( RefContext<'b, 'g, 'r, 's>, OrgSource<'s>, OrgSource<'s>, - Vec>, + AK, ) -> Res, Element<'s>> - + 's { + + 's +where + AK: IntoIterator>, +{ let context_name = format!("special block {}", name); move |context, input, pre_affiliated_keywords_input, affiliated_keywords| { _special_block( @@ -175,14 +186,17 @@ fn special_block<'s>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -fn _special_block<'c, 'b, 'g, 'r, 's>( +fn _special_block<'c, 'b, 'g, 'r, 's, AK>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, pre_affiliated_keywords_input: OrgSource<'s>, name: &'s str, context_name: &'c str, - affiliated_keywords: Vec>, -) -> Res, Element<'s>> { + affiliated_keywords: AK, +) -> Res, Element<'s>> +where + AK: IntoIterator>, +{ let (remaining, parameters) = opt(tuple((space1, parameters)))(input)?; let (remaining, (source, children)) = greater_block_body( context, From d1223dcdb717fa20e69fa8d04358db7ef7f97f00 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:37:31 -0400 Subject: [PATCH 07/15] Port paragraph parser to use ak_element. --- src/parser/element_parser.rs | 53 ++++++++++++------------------------ src/parser/macros.rs | 15 ++++++++++ src/parser/paragraph.rs | 11 ++++++-- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index ef67395f..cb17c630 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -98,7 +98,6 @@ fn _element<'b, 'g, 'r, 's>( let horizontal_rule_matcher = parser_with_context!(horizontal_rule)(context); let keyword_matcher = parser_with_context!(keyword)(context); let babel_keyword_matcher = parser_with_context!(babel_call)(context); - let paragraph_matcher = parser_with_context!(paragraph)(context); let latex_environment_matcher = parser_with_context!(latex_environment)(context); let (mut remaining, mut maybe_element) = { @@ -128,41 +127,25 @@ fn _element<'b, 'g, 'r, 's>( )))(input)? }; - if maybe_element.is_none() && can_be_paragraph { - #[cfg(feature = "tracing")] - let span = span!(tracing::Level::DEBUG, "Paragraph with affiliated keyword."); - #[cfg(feature = "tracing")] - let _enter = span.enter(); + // Paragraph with affiliated keyword + ak_element!( + paragraph, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::Paragraph + ); - let (remain, paragraph_with_affiliated_keyword) = opt(map( - tuple(( - peek(affiliated_keyword), - map(paragraph_matcher, Element::Paragraph), - )), - |(_, paragraph)| paragraph, - ))(remaining)?; - if paragraph_with_affiliated_keyword.is_some() { - remaining = remain; - maybe_element = paragraph_with_affiliated_keyword; - } - } - - // TODO: These two paragraphs need to be revisited using the affiliated keywords parsed above. - - if maybe_element.is_none() && can_be_paragraph { - #[cfg(feature = "tracing")] - let span = span!( - tracing::Level::DEBUG, - "Paragraph without affiliated keyword." - ); - #[cfg(feature = "tracing")] - let _enter = span.enter(); - - let (remain, paragraph_without_affiliated_keyword) = - map(paragraph_matcher, Element::Paragraph)(remaining)?; - remaining = remain; - maybe_element = Some(paragraph_without_affiliated_keyword); - } + // Paragraph without affiliated keyword + ak_element!( + paragraph, + std::iter::empty(), + input, + context, + input, + Element::Paragraph + ); if maybe_element.is_none() { return Err(nom::Err::Error(CustomError::MyError(MyError( diff --git a/src/parser/macros.rs b/src/parser/macros.rs index 86659baf..f2e07bab 100644 --- a/src/parser/macros.rs +++ b/src/parser/macros.rs @@ -23,3 +23,18 @@ macro_rules! ak_element { } pub(crate) use ak_element; + +macro_rules! element { + ($parser:ident, $context: expr, $input: expr, $wrapper: expr) => { + if let Ok((remaining, ele)) = $parser($context, $input) { + return Ok((remaining, $wrapper(ele))); + } + }; + ($parser:ident, $context: expr, $input: expr) => { + if let Ok((remaining, ele)) = $parser($context, $input) { + return Ok((remaining, ele)); + } + }; +} + +pub(crate) use element; diff --git a/src/parser/paragraph.rs b/src/parser/paragraph.rs index 90331eb3..91e8fbcf 100644 --- a/src/parser/paragraph.rs +++ b/src/parser/paragraph.rs @@ -23,17 +23,22 @@ use crate::error::Res; use crate::parser::object_parser::standard_set_object; use crate::parser::util::exit_matcher_parser; use crate::parser::util::start_of_line; +use crate::types::Keyword; use crate::types::Paragraph; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn paragraph<'b, 'g, 'r, 's>( +pub(crate) fn paragraph<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, Paragraph<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, Paragraph<'s>> +where + AK: IntoIterator>, +{ let contexts = [ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Gamma, exit_matcher: ¶graph_end, From 9ccdcaac24cc472780ff4cb4f7eb9b1692e216f8 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:46:15 -0400 Subject: [PATCH 08/15] Port dynamic block. --- src/parser/dynamic_block.rs | 12 +++++--- src/parser/element_parser.rs | 53 ++++++++++++++++++++---------------- src/parser/paragraph.rs | 2 -- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/parser/dynamic_block.rs b/src/parser/dynamic_block.rs index 6086176e..3a7984cd 100644 --- a/src/parser/dynamic_block.rs +++ b/src/parser/dynamic_block.rs @@ -18,7 +18,6 @@ use nom::sequence::preceded; use nom::sequence::tuple; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; use crate::context::parser_with_context; @@ -37,6 +36,7 @@ use crate::parser::util::immediate_in_section; use crate::parser::util::start_of_line; use crate::types::DynamicBlock; use crate::types::Element; +use crate::types::Keyword; use crate::types::Paragraph; use crate::types::SetSource; @@ -44,16 +44,20 @@ use crate::types::SetSource; feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn dynamic_block<'b, 'g, 'r, 's>( +pub(crate) fn dynamic_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, DynamicBlock<'s>> { +) -> Res, DynamicBlock<'s>> +where + AK: IntoIterator>, +{ if immediate_in_section(context, "dynamic block") { return Err(nom::Err::Error(CustomError::MyError(MyError( "Cannot nest objects of the same element".into(), )))); } - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; start_of_line(remaining)?; let (remaining, _leading_whitespace) = space0(remaining)?; diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index cb17c630..a7400ecb 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -1,9 +1,7 @@ use nom::branch::alt; use nom::combinator::map; use nom::combinator::opt; -use nom::combinator::peek; use nom::multi::many0; -use nom::sequence::tuple; #[cfg(feature = "tracing")] use tracing::span; @@ -82,7 +80,15 @@ fn _element<'b, 'g, 'r, 's>( input ); - let dynamic_block_matcher = parser_with_context!(dynamic_block)(context); + ak_element!( + dynamic_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::DynamicBlock + ); + 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); @@ -100,14 +106,13 @@ fn _element<'b, 'g, 'r, 's>( let babel_keyword_matcher = parser_with_context!(babel_call)(context); let latex_environment_matcher = parser_with_context!(latex_environment)(context); - let (mut remaining, mut maybe_element) = { + let (remaining, maybe_element) = { #[cfg(feature = "tracing")] let span = span!(tracing::Level::DEBUG, "Main element block"); #[cfg(feature = "tracing")] let _enter = span.enter(); opt(alt(( - map(dynamic_block_matcher, Element::DynamicBlock), map(footnote_definition_matcher, Element::FootnoteDefinition), map(comment_matcher, Element::Comment), map(drawer_matcher, Element::Drawer), @@ -127,25 +132,27 @@ fn _element<'b, 'g, 'r, 's>( )))(input)? }; - // Paragraph with affiliated keyword - ak_element!( - paragraph, - &mut affiliated_keywords, - post_affiliated_keywords_input, - context, - input, - Element::Paragraph - ); + if can_be_paragraph { + // Paragraph with affiliated keyword + ak_element!( + paragraph, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::Paragraph + ); - // Paragraph without affiliated keyword - ak_element!( - paragraph, - std::iter::empty(), - input, - context, - input, - Element::Paragraph - ); + // Paragraph without affiliated keyword + ak_element!( + paragraph, + std::iter::empty(), + input, + context, + input, + Element::Paragraph + ); + } if maybe_element.is_none() { return Err(nom::Err::Error(CustomError::MyError(MyError( diff --git a/src/parser/paragraph.rs b/src/parser/paragraph.rs index 91e8fbcf..cd8ce7e2 100644 --- a/src/parser/paragraph.rs +++ b/src/parser/paragraph.rs @@ -2,14 +2,12 @@ use nom::branch::alt; use nom::combinator::eof; use nom::combinator::recognize; use nom::combinator::verify; -use nom::multi::many0; use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; use super::affiliated_keyword::parse_affiliated_keywords; use super::element_parser::detect_element; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::blank_line; use super::util::get_consumed; From 1411aca7b527526f4fb7e88f4e52033a02e3fb9e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:48:50 -0400 Subject: [PATCH 09/15] Port footnote definition. --- src/parser/element_parser.rs | 11 +++++++++-- src/parser/footnote_definition.rs | 11 ++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index a7400ecb..1188a30b 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -89,7 +89,15 @@ fn _element<'b, 'g, 'r, 's>( Element::DynamicBlock ); - let footnote_definition_matcher = parser_with_context!(footnote_definition)(context); + ak_element!( + footnote_definition, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::FootnoteDefinition + ); + 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); @@ -113,7 +121,6 @@ fn _element<'b, 'g, 'r, 's>( let _enter = span.enter(); opt(alt(( - map(footnote_definition_matcher, Element::FootnoteDefinition), map(comment_matcher, Element::Comment), map(drawer_matcher, Element::Drawer), map(table_matcher, Element::Table), diff --git a/src/parser/footnote_definition.rs b/src/parser/footnote_definition.rs index 1ce9aef9..8b669cd1 100644 --- a/src/parser/footnote_definition.rs +++ b/src/parser/footnote_definition.rs @@ -33,21 +33,26 @@ use crate::parser::util::immediate_in_section; use crate::parser::util::maybe_consume_trailing_whitespace; use crate::parser::util::start_of_line; use crate::types::FootnoteDefinition; +use crate::types::Keyword; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn footnote_definition<'b, 'g, 'r, 's>( +pub(crate) fn footnote_definition<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, FootnoteDefinition<'s>> { +) -> Res, FootnoteDefinition<'s>> +where + AK: IntoIterator>, +{ if immediate_in_section(context, "footnote definition") { return Err(nom::Err::Error(CustomError::MyError(MyError( "Cannot nest objects of the same element".into(), )))); } - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; start_of_line(remaining)?; // Cannot be indented. let (remaining, (_, lbl, _, _, _)) = tuple(( From 767f44f94d5ca78800b0f7a615c772c64ecc739d Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 16:52:49 -0400 Subject: [PATCH 10/15] Port comment. --- src/parser/element_parser.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 1188a30b..141c295b 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -38,6 +38,7 @@ use crate::error::CustomError; use crate::error::MyError; use crate::error::Res; use crate::parser::macros::ak_element; +use crate::parser::macros::element; use crate::parser::table::org_mode_table; use crate::types::Element; @@ -98,7 +99,8 @@ fn _element<'b, 'g, 'r, 's>( Element::FootnoteDefinition ); - let comment_matcher = parser_with_context!(comment)(context); + element!(comment, context, input, Element::Comment); + 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); @@ -121,7 +123,6 @@ fn _element<'b, 'g, 'r, 's>( let _enter = span.enter(); opt(alt(( - map(comment_matcher, Element::Comment), map(drawer_matcher, Element::Drawer), map(table_matcher, Element::Table), map(verse_block_matcher, Element::VerseBlock), From f475754a7162f017e20e3cf0ff4f55743b5e77f2 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 17:12:55 -0400 Subject: [PATCH 11/15] Port the rest of the element parsers over. --- src/parser/babel_call.rs | 12 ++- src/parser/diary_sexp.rs | 11 ++- src/parser/drawer.rs | 11 ++- src/parser/element_parser.rs | 163 +++++++++++++++++++++++--------- src/parser/fixed_width_area.rs | 11 ++- src/parser/horizontal_rule.rs | 11 ++- src/parser/keyword.rs | 10 +- src/parser/latex_environment.rs | 11 ++- src/parser/lesser_block.rs | 51 +++++++--- src/parser/table.rs | 11 ++- 10 files changed, 218 insertions(+), 84 deletions(-) diff --git a/src/parser/babel_call.rs b/src/parser/babel_call.rs index eaeae758..629113c9 100644 --- a/src/parser/babel_call.rs +++ b/src/parser/babel_call.rs @@ -28,17 +28,21 @@ use crate::error::Res; use crate::parser::util::get_consumed; use crate::parser::util::org_line_ending; use crate::types::BabelCall; +use crate::types::Keyword; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn babel_call<'b, 'g, 'r, 's>( +pub(crate) fn babel_call<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, BabelCall<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; - +) -> Res, BabelCall<'s>> +where + AK: IntoIterator>, +{ start_of_line(remaining)?; let (remaining, _) = tuple((space0, tag("#+"), tag_no_case("call"), tag(":")))(remaining)?; diff --git a/src/parser/diary_sexp.rs b/src/parser/diary_sexp.rs index 698b30f0..5b2cbfe5 100644 --- a/src/parser/diary_sexp.rs +++ b/src/parser/diary_sexp.rs @@ -14,16 +14,21 @@ use crate::error::Res; use crate::parser::util::get_consumed; use crate::parser::util::start_of_line; use crate::types::DiarySexp; +use crate::types::Keyword; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn diary_sexp<'b, 'g, 'r, 's>( +pub(crate) fn diary_sexp<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, DiarySexp<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, DiarySexp<'s>> +where + AK: IntoIterator>, +{ start_of_line(remaining)?; let (remaining, value) = recognize(tuple((tag("%%("), is_not("\r\n"))))(remaining)?; let (remaining, _eol) = org_line_ending(remaining)?; diff --git a/src/parser/drawer.rs b/src/parser/drawer.rs index 438a0074..0123e13c 100644 --- a/src/parser/drawer.rs +++ b/src/parser/drawer.rs @@ -32,6 +32,7 @@ use crate::parser::util::start_of_line; use crate::parser::util::WORD_CONSTITUENT_CHARACTERS; use crate::types::Drawer; use crate::types::Element; +use crate::types::Keyword; use crate::types::Paragraph; use crate::types::SetSource; @@ -39,16 +40,20 @@ use crate::types::SetSource; feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn drawer<'b, 'g, 'r, 's>( +pub(crate) fn drawer<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, Drawer<'s>> { +) -> Res, Drawer<'s>> +where + AK: IntoIterator>, +{ if immediate_in_section(context, "drawer") { return Err(nom::Err::Error(CustomError::MyError(MyError( "Cannot nest objects of the same element".into(), )))); } - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; start_of_line(remaining)?; let (remaining, _leading_whitespace) = space0(remaining)?; let (remaining, (_open_colon, drawer_name, _close_colon, _new_line)) = tuple(( diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 141c295b..4a830eb1 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -101,44 +101,124 @@ fn _element<'b, 'g, 'r, 's>( element!(comment, context, input, Element::Comment); - 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 babel_keyword_matcher = parser_with_context!(babel_call)(context); - let latex_environment_matcher = parser_with_context!(latex_environment)(context); + ak_element!( + drawer, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::Drawer + ); - let (remaining, maybe_element) = { - #[cfg(feature = "tracing")] - let span = span!(tracing::Level::DEBUG, "Main element block"); - #[cfg(feature = "tracing")] - let _enter = span.enter(); + ak_element!( + org_mode_table, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::Table + ); - opt(alt(( - 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(latex_environment_matcher, Element::LatexEnvironment), - map(babel_keyword_matcher, Element::BabelCall), - map(keyword_matcher, Element::Keyword), - )))(input)? - }; + ak_element!( + verse_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::VerseBlock + ); + + ak_element!( + comment_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::CommentBlock + ); + + ak_element!( + example_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::ExampleBlock + ); + + ak_element!( + export_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::ExportBlock + ); + + ak_element!( + src_block, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::SrcBlock + ); + + element!(clock, context, input, Element::Clock); + + ak_element!( + diary_sexp, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::DiarySexp + ); + + ak_element!( + fixed_width_area, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::FixedWidthArea + ); + + ak_element!( + horizontal_rule, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::HorizontalRule + ); + + ak_element!( + latex_environment, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::LatexEnvironment + ); + + ak_element!( + babel_call, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::BabelCall + ); + + ak_element!( + keyword, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::Keyword + ); if can_be_paragraph { // Paragraph with affiliated keyword @@ -162,14 +242,9 @@ fn _element<'b, 'g, 'r, 's>( ); } - if maybe_element.is_none() { - return Err(nom::Err::Error(CustomError::MyError(MyError( - "No element.", - )))); - } - let element = maybe_element.expect("The above if-statement ensures this is Some()."); - - Ok((remaining, element)) + Err(nom::Err::Error(CustomError::MyError(MyError( + "No element.", + )))) } pub(crate) const fn detect_element( diff --git a/src/parser/fixed_width_area.rs b/src/parser/fixed_width_area.rs index 0260784d..642e824d 100644 --- a/src/parser/fixed_width_area.rs +++ b/src/parser/fixed_width_area.rs @@ -21,16 +21,21 @@ use crate::parser::util::exit_matcher_parser; use crate::parser::util::get_consumed; use crate::parser::util::start_of_line; use crate::types::FixedWidthArea; +use crate::types::Keyword; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>( +pub(crate) fn fixed_width_area<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, FixedWidthArea<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, FixedWidthArea<'s>> +where + AK: IntoIterator>, +{ let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context); let exit_matcher = parser_with_context!(exit_matcher_parser)(context); let (remaining, first_line) = fixed_width_area_line_matcher(remaining)?; diff --git a/src/parser/horizontal_rule.rs b/src/parser/horizontal_rule.rs index d331f91b..a51bb9a5 100644 --- a/src/parser/horizontal_rule.rs +++ b/src/parser/horizontal_rule.rs @@ -18,16 +18,21 @@ use crate::context::RefContext; use crate::error::Res; use crate::parser::util::start_of_line; use crate::types::HorizontalRule; +use crate::types::Keyword; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>( +pub(crate) fn horizontal_rule<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, HorizontalRule<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, HorizontalRule<'s>> +where + AK: IntoIterator>, +{ start_of_line(remaining)?; let (remaining, _rule) = recognize(tuple(( space0, diff --git a/src/parser/keyword.rs b/src/parser/keyword.rs index 4e5eb1b9..5f457f63 100644 --- a/src/parser/keyword.rs +++ b/src/parser/keyword.rs @@ -94,11 +94,15 @@ fn _filtered_keyword<'s, F: Matcher>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn keyword<'b, 'g, 'r, 's>( +pub(crate) fn keyword<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, Keyword<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, Keyword<'s>> +where + AK: IntoIterator>, +{ let (remaining, mut kw) = filtered_keyword(regular_keyword_key)(remaining)?; let (remaining, _trailing_ws) = maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; diff --git a/src/parser/latex_environment.rs b/src/parser/latex_environment.rs index 44002f51..f9d6c163 100644 --- a/src/parser/latex_environment.rs +++ b/src/parser/latex_environment.rs @@ -26,17 +26,22 @@ use crate::context::RefContext; use crate::error::Res; use crate::parser::util::exit_matcher_parser; use crate::parser::util::start_of_line; +use crate::types::Keyword; use crate::types::LatexEnvironment; #[cfg_attr( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn latex_environment<'b, 'g, 'r, 's>( +pub(crate) fn latex_environment<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, LatexEnvironment<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, LatexEnvironment<'s>> +where + AK: IntoIterator>, +{ let value_start = remaining; start_of_line(remaining)?; let (remaining, _leading_whitespace) = space0(remaining)?; diff --git a/src/parser/lesser_block.rs b/src/parser/lesser_block.rs index 2870c82c..e7a3b3c3 100644 --- a/src/parser/lesser_block.rs +++ b/src/parser/lesser_block.rs @@ -41,6 +41,7 @@ use crate::types::CharOffsetInLine; use crate::types::CommentBlock; use crate::types::ExampleBlock; use crate::types::ExportBlock; +use crate::types::Keyword; use crate::types::LineNumber; use crate::types::Object; use crate::types::PlainText; @@ -53,11 +54,15 @@ use crate::types::VerseBlock; feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn verse_block<'b, 'g, 'r, 's>( +pub(crate) fn verse_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, VerseBlock<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, VerseBlock<'s>> +where + AK: IntoIterator>, +{ let (remaining, _) = lesser_block_begin("verse")(context, remaining)?; let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; @@ -117,11 +122,15 @@ pub(crate) fn verse_block<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn comment_block<'b, 'g, 'r, 's>( +pub(crate) fn comment_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, CommentBlock<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, CommentBlock<'s>> +where + AK: IntoIterator>, +{ let (remaining, _) = lesser_block_begin("comment")(context, remaining)?; let (remaining, _parameters) = opt(tuple((space1, data)))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; @@ -161,11 +170,15 @@ pub(crate) fn comment_block<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn example_block<'b, 'g, 'r, 's>( +pub(crate) fn example_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, ExampleBlock<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, ExampleBlock<'s>> +where + AK: IntoIterator>, +{ let (remaining, _) = lesser_block_begin("example")(context, remaining)?; let (remaining, parameters) = opt(alt(( map(tuple((space1, example_switches)), |(_, switches)| switches), @@ -238,11 +251,15 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn export_block<'b, 'g, 'r, 's>( +pub(crate) fn export_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, ExportBlock<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, ExportBlock<'s>> +where + AK: IntoIterator>, +{ let (remaining, _) = lesser_block_begin("export")(context, remaining)?; // https://orgmode.org/worg/org-syntax.html#Blocks claims that export blocks must have a single word for data but testing shows no data and multi-word data still parses as an export block. let (remaining, export_type) = opt(map( @@ -290,11 +307,15 @@ pub(crate) fn export_block<'b, 'g, 'r, 's>( feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn src_block<'b, 'g, 'r, 's>( +pub(crate) fn src_block<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, SrcBlock<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, SrcBlock<'s>> +where + AK: IntoIterator>, +{ let (remaining, _) = lesser_block_begin("src")(context, remaining)?; // https://orgmode.org/worg/org-syntax.html#Blocks claims that data is mandatory and must follow the LANGUAGE SWITCHES ARGUMENTS pattern but testing has shown that no data and incorrect data here will still parse to a src block. let (remaining, language) = diff --git a/src/parser/table.rs b/src/parser/table.rs index 857a55de..e8f615da 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -29,6 +29,7 @@ use crate::context::RefContext; use crate::error::Res; use crate::parser::util::get_consumed; use crate::parser::util::start_of_line; +use crate::types::Keyword; use crate::types::Table; use crate::types::TableCell; use crate::types::TableRow; @@ -40,11 +41,15 @@ use crate::types::TableRow; feature = "tracing", tracing::instrument(ret, level = "debug", skip(context)) )] -pub(crate) fn org_mode_table<'b, 'g, 'r, 's>( +pub(crate) fn org_mode_table<'b, 'g, 'r, 's, AK>( + affiliated_keywords: AK, + remaining: OrgSource<'s>, context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, -) -> Res, Table<'s>> { - let (remaining, affiliated_keywords) = many0(affiliated_keyword)(input)?; +) -> Res, Table<'s>> +where + AK: IntoIterator>, +{ start_of_line(remaining)?; peek(tuple((space0, tag("|"))))(remaining)?; From 5ae19e455d46afc3c58b9c598d38d9f4813ba0e8 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 17:14:18 -0400 Subject: [PATCH 12/15] Remove unused imports. --- src/parser/babel_call.rs | 2 -- src/parser/drawer.rs | 2 -- src/parser/element_parser.rs | 2 -- src/parser/horizontal_rule.rs | 2 -- src/parser/keyword.rs | 1 - src/parser/latex_environment.rs | 2 -- src/parser/lesser_block.rs | 2 -- 7 files changed, 13 deletions(-) diff --git a/src/parser/babel_call.rs b/src/parser/babel_call.rs index 629113c9..a40f0764 100644 --- a/src/parser/babel_call.rs +++ b/src/parser/babel_call.rs @@ -9,13 +9,11 @@ use nom::combinator::opt; use nom::combinator::peek; use nom::combinator::recognize; use nom::combinator::verify; -use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; use nom::InputTake; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::BracketDepth; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; use super::util::start_of_line; diff --git a/src/parser/drawer.rs b/src/parser/drawer.rs index 0123e13c..8c6f27cb 100644 --- a/src/parser/drawer.rs +++ b/src/parser/drawer.rs @@ -7,12 +7,10 @@ use nom::character::complete::space0; use nom::combinator::eof; use nom::combinator::not; use nom::combinator::recognize; -use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; use crate::context::parser_with_context; diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 4a830eb1..3535b0c8 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -1,6 +1,4 @@ use nom::branch::alt; -use nom::combinator::map; -use nom::combinator::opt; use nom::multi::many0; #[cfg(feature = "tracing")] use tracing::span; diff --git a/src/parser/horizontal_rule.rs b/src/parser/horizontal_rule.rs index a51bb9a5..ec45d95c 100644 --- a/src/parser/horizontal_rule.rs +++ b/src/parser/horizontal_rule.rs @@ -5,12 +5,10 @@ use nom::character::complete::space0; use nom::combinator::eof; use nom::combinator::recognize; use nom::combinator::verify; -use nom::multi::many0; use nom::multi::many1_count; use nom::sequence::tuple; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::get_consumed; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; diff --git a/src/parser/keyword.rs b/src/parser/keyword.rs index 5f457f63..24a5f891 100644 --- a/src/parser/keyword.rs +++ b/src/parser/keyword.rs @@ -13,7 +13,6 @@ use nom::combinator::not; use nom::combinator::peek; use nom::combinator::recognize; use nom::combinator::verify; -use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; diff --git a/src/parser/latex_environment.rs b/src/parser/latex_environment.rs index f9d6c163..af41d91d 100644 --- a/src/parser/latex_environment.rs +++ b/src/parser/latex_environment.rs @@ -8,12 +8,10 @@ use nom::character::complete::space0; use nom::combinator::eof; use nom::combinator::peek; use nom::combinator::recognize; -use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::get_consumed; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; diff --git a/src/parser/lesser_block.rs b/src/parser/lesser_block.rs index e7a3b3c3..37f30918 100644 --- a/src/parser/lesser_block.rs +++ b/src/parser/lesser_block.rs @@ -13,13 +13,11 @@ use nom::combinator::opt; use nom::combinator::peek; use nom::combinator::recognize; use nom::combinator::verify; -use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; use nom::InputTake; use super::affiliated_keyword::parse_affiliated_keywords; -use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::maybe_consume_trailing_whitespace_if_not_exiting; use crate::context::parser_with_context; From e6e3783ec65b7bcc872c00aaaef02185eac74e17 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 17:23:54 -0400 Subject: [PATCH 13/15] Support parsing affiliated keywords as keywords. --- src/parser/element_parser.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 3535b0c8..92b10896 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -209,6 +209,7 @@ fn _element<'b, 'g, 'r, 's>( Element::BabelCall ); + // Keyword with affiliated keywords ak_element!( keyword, &mut affiliated_keywords, @@ -218,6 +219,16 @@ fn _element<'b, 'g, 'r, 's>( Element::Keyword ); + // Keyword without affiliated keywords + ak_element!( + keyword, + std::iter::empty(), + input, + context, + input, + Element::Keyword + ); + if can_be_paragraph { // Paragraph with affiliated keyword ak_element!( From c039e0d62cd9d55b49f8fd2411e8dc57102a1f5e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 17:32:29 -0400 Subject: [PATCH 14/15] Keywords without affiliated keywords should be lower priority than paragraphs with affiliated keywords. --- src/parser/element_parser.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 92b10896..bf043882 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -219,6 +219,18 @@ fn _element<'b, 'g, 'r, 's>( Element::Keyword ); + if can_be_paragraph { + // Paragraph with affiliated keyword + ak_element!( + paragraph, + &mut affiliated_keywords, + post_affiliated_keywords_input, + context, + input, + Element::Paragraph + ); + } + // Keyword without affiliated keywords ak_element!( keyword, @@ -230,16 +242,6 @@ fn _element<'b, 'g, 'r, 's>( ); if can_be_paragraph { - // Paragraph with affiliated keyword - ak_element!( - paragraph, - &mut affiliated_keywords, - post_affiliated_keywords_input, - context, - input, - Element::Paragraph - ); - // Paragraph without affiliated keyword ak_element!( paragraph, From 68f8e04ee814359bb7f08d2691693f1c5f92fa55 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 12 Oct 2023 17:46:25 -0400 Subject: [PATCH 15/15] Add tests for affiliated keywords before elements that cannot have affiliated keywords. --- org_mode_samples/greater_element/plain_list/item/name.org | 3 +++ org_mode_samples/greater_element/property_drawer/name.org | 5 +++++ org_mode_samples/greater_element/table/row/name.org | 3 +++ org_mode_samples/sections_and_headings/name.org | 3 +++ 4 files changed, 14 insertions(+) create mode 100644 org_mode_samples/greater_element/plain_list/item/name.org create mode 100644 org_mode_samples/greater_element/property_drawer/name.org create mode 100644 org_mode_samples/greater_element/table/row/name.org create mode 100644 org_mode_samples/sections_and_headings/name.org diff --git a/org_mode_samples/greater_element/plain_list/item/name.org b/org_mode_samples/greater_element/plain_list/item/name.org new file mode 100644 index 00000000..0ae0f101 --- /dev/null +++ b/org_mode_samples/greater_element/plain_list/item/name.org @@ -0,0 +1,3 @@ +1. foo +#+NAME: bar +2. baz diff --git a/org_mode_samples/greater_element/property_drawer/name.org b/org_mode_samples/greater_element/property_drawer/name.org new file mode 100644 index 00000000..381edd3a --- /dev/null +++ b/org_mode_samples/greater_element/property_drawer/name.org @@ -0,0 +1,5 @@ +* Overwrite + #+NAME: foo + :PROPERTIES: + :header-args: :var foo="lorem" + :END: diff --git a/org_mode_samples/greater_element/table/row/name.org b/org_mode_samples/greater_element/table/row/name.org new file mode 100644 index 00000000..2719eced --- /dev/null +++ b/org_mode_samples/greater_element/table/row/name.org @@ -0,0 +1,3 @@ +|foo| +#+NAME: bar +|baz | diff --git a/org_mode_samples/sections_and_headings/name.org b/org_mode_samples/sections_and_headings/name.org new file mode 100644 index 00000000..b5f03662 --- /dev/null +++ b/org_mode_samples/sections_and_headings/name.org @@ -0,0 +1,3 @@ +#+NAME: foo +* bar +#+NAME: baz