Re-work the element parser to handle affiliated keywords before elements that cannot have affiliated keywords.

This commit is contained in:
Tom Alexander 2023-10-04 22:47:13 -04:00
parent b82d4c0eca
commit 65eda08843
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -1,5 +1,10 @@
use nom::branch::alt; use nom::branch::alt;
use nom::combinator::map; use nom::combinator::map;
use nom::combinator::opt;
use nom::combinator::peek;
use nom::sequence::tuple;
#[cfg(feature = "tracing")]
use tracing::span;
use super::clock::clock; use super::clock::clock;
use super::comment::comment; use super::comment::comment;
@ -75,43 +80,104 @@ fn _element<'b, 'g, 'r, 's>(
let paragraph_matcher = parser_with_context!(paragraph)(context); let paragraph_matcher = parser_with_context!(paragraph)(context);
let latex_environment_matcher = parser_with_context!(latex_environment)(context); let latex_environment_matcher = parser_with_context!(latex_environment)(context);
let (remaining, mut element) = match alt(( let (mut remaining, mut maybe_element) = {
map(plain_list_matcher, Element::PlainList), #[cfg(feature = "tracing")]
greater_block_matcher, let span = span!(tracing::Level::DEBUG, "Main element block");
map(dynamic_block_matcher, Element::DynamicBlock), #[cfg(feature = "tracing")]
map(footnote_definition_matcher, Element::FootnoteDefinition), let _enter = span.enter();
map(comment_matcher, Element::Comment),
map(drawer_matcher, Element::Drawer), opt(alt((
map(table_matcher, Element::Table), map(plain_list_matcher, Element::PlainList),
map(verse_block_matcher, Element::VerseBlock), greater_block_matcher,
map(comment_block_matcher, Element::CommentBlock), map(dynamic_block_matcher, Element::DynamicBlock),
map(example_block_matcher, Element::ExampleBlock), map(footnote_definition_matcher, Element::FootnoteDefinition),
map(export_block_matcher, Element::ExportBlock), map(comment_matcher, Element::Comment),
map(src_block_matcher, Element::SrcBlock), map(drawer_matcher, Element::Drawer),
map(clock_matcher, Element::Clock), map(table_matcher, Element::Table),
map(diary_sexp_matcher, Element::DiarySexp), map(verse_block_matcher, Element::VerseBlock),
map(fixed_width_area_matcher, Element::FixedWidthArea), map(comment_block_matcher, Element::CommentBlock),
map(horizontal_rule_matcher, Element::HorizontalRule), map(example_block_matcher, Element::ExampleBlock),
map(latex_environment_matcher, Element::LatexEnvironment), map(export_block_matcher, Element::ExportBlock),
map(babel_keyword_matcher, Element::BabelCall), map(src_block_matcher, Element::SrcBlock),
map(keyword_matcher, Element::Keyword), map(clock_matcher, Element::Clock),
))(input) map(diary_sexp_matcher, Element::DiarySexp),
{ map(fixed_width_area_matcher, Element::FixedWidthArea),
the_ok @ Ok(_) => the_ok, map(horizontal_rule_matcher, Element::HorizontalRule),
Err(_) => { map(latex_environment_matcher, Element::LatexEnvironment),
if can_be_paragraph { map(babel_keyword_matcher, Element::BabelCall),
match map(paragraph_matcher, Element::Paragraph)(input) { map(keyword_matcher, Element::Keyword),
the_ok @ Ok(_) => the_ok, )))(input)?
Err(_) => { };
// TODO: Because this function expects a single element, if there are multiple affiliated keywords before an element that cannot have affiliated keywords, we end up re-parsing the affiliated keywords many times.
map(affiliated_keyword, Element::Keyword)(input) if maybe_element.is_none() && can_be_paragraph {
} #[cfg(feature = "tracing")]
} let span = span!(tracing::Level::DEBUG, "Paragraph with affiliated keyword.");
} else { #[cfg(feature = "tracing")]
map(affiliated_keyword, Element::Keyword)(input) let _enter = span.enter();
}
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;
} }
}?; }
// if maybe_element.is_none() {
// #[cfg(feature = "tracing")]
// let span = span!(tracing::Level::DEBUG, "Regular keyword.");
// #[cfg(feature = "tracing")]
// let _enter = span.enter();
// let (remain, kw) = opt(map(keyword_matcher, Element::Keyword))(remaining)?;
// if kw.is_some() {
// maybe_element = kw;
// remaining = remain;
// }
// }
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(affiliated_keyword, 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!(
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);
}
if maybe_element.is_none() {
return Err(nom::Err::Error(CustomError::MyError(MyError(
"No element.",
))));
}
let mut element = maybe_element.expect("The above if-statement ensures this is Some().");
let (remaining, _trailing_ws) = let (remaining, _trailing_ws) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;