From ec813e3b3f0f5ea9a82426afa0145fc1df425d87 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 28 Aug 2023 00:24:27 -0400 Subject: [PATCH] Switch to using bracket depth from OrgSource instead of from the context for footnote references. It is currently unknown if this will produce a performance increase, but unless it has a significant performance penalty we are going to go forward with this change because it makes it more explicit which values need to be read deeply from other elements (therefore needing to be in the context) vs values that can be bound to the exit matcher since they are only used within the confines of the current element. I suspect we will get a performance boost since it will be reducing the nodes that need to be walked in the context but maintaining bracket depth count over the entire document instead of only inside elements that need balanced brackets could cost us. --- .../footnote_reference/balanced_brackets.org | 2 + src/parser/footnote_reference.rs | 82 ++++++------------- src/parser/parser_context.rs | 18 ---- 3 files changed, 28 insertions(+), 74 deletions(-) create mode 100644 org_mode_samples/object/footnote_reference/balanced_brackets.org diff --git a/org_mode_samples/object/footnote_reference/balanced_brackets.org b/org_mode_samples/object/footnote_reference/balanced_brackets.org new file mode 100644 index 00000000..251c9add --- /dev/null +++ b/org_mode_samples/object/footnote_reference/balanced_brackets.org @@ -0,0 +1,2 @@ +[fn:2:This footnote [ has balanced ] brackets inside it] +[fn::This footnote does not have balanced [ brackets inside it] diff --git a/src/parser/footnote_reference.rs b/src/parser/footnote_reference.rs index ad35b9ac..340e4c81 100644 --- a/src/parser/footnote_reference.rs +++ b/src/parser/footnote_reference.rs @@ -15,7 +15,6 @@ use crate::parser::exiting::ExitClass; use crate::parser::footnote_definition::label; use crate::parser::object_parser::standard_set_object; use crate::parser::parser_context::ExitMatcherNode; -use crate::parser::parser_context::FootnoteReferenceDefinition; use crate::parser::parser_with_context::parser_with_context; use crate::parser::util::exit_matcher_parser; use crate::parser::util::get_consumed; @@ -39,18 +38,12 @@ fn anonymous_footnote<'r, 's>( input: OrgSource<'s>, ) -> Res, FootnoteReference<'s>> { let (remaining, _) = tag_no_case("[fn::")(input)?; - let parser_context = context - .with_additional_node(ContextElement::FootnoteReferenceDefinition( - FootnoteReferenceDefinition { - position: remaining, - depth: 0, - }, - )) - .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + let exit_with_depth = footnote_definition_end(remaining.get_bracket_depth()); + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Beta, - exit_matcher: &footnote_definition_end, + exit_matcher: &exit_with_depth, })); - // TODO: I could insert FootnoteReferenceDefinition entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient. let (remaining, (children, _exit_contents)) = verify( many_till( parser_with_context!(standard_set_object)(&parser_context), @@ -80,18 +73,12 @@ fn inline_footnote<'r, 's>( let (remaining, _) = tag_no_case("[fn:")(input)?; let (remaining, label_contents) = label(remaining)?; let (remaining, _) = tag(":")(remaining)?; - let parser_context = context - .with_additional_node(ContextElement::FootnoteReferenceDefinition( - FootnoteReferenceDefinition { - position: remaining, - depth: 0, - }, - )) - .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + let exit_with_depth = footnote_definition_end(remaining.get_bracket_depth()); + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Beta, - exit_matcher: &footnote_definition_end, + exit_matcher: &exit_with_depth, })); - // TODO: I could insert FootnoteReferenceDefinition entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient. let (remaining, (children, _exit_contents)) = verify( many_till( parser_with_context!(standard_set_object)(&parser_context), @@ -133,47 +120,30 @@ fn footnote_reference_only<'r, 's>( )) } -#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn footnote_definition_end<'r, 's>( - context: Context<'r, 's>, - input: OrgSource<'s>, -) -> Res, OrgSource<'s>> { - let context_depth = get_bracket_depth(context) - .expect("This function should only be called from inside a footnote definition."); - let text_since_context_entry = get_consumed(context_depth.position, input); - let mut current_depth = context_depth.depth; - for c in Into::<&str>::into(text_since_context_entry).chars() { - match c { - '[' => { - current_depth += 1; - } - ']' if current_depth == 0 => { - panic!("Exceeded footnote reference definition bracket depth.") - } - ']' if current_depth > 0 => { - current_depth -= 1; - } - _ => {} - } +fn footnote_definition_end( + starting_bracket_depth: isize, +) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res, OrgSource<'s>> { + move |context: Context, input: OrgSource<'_>| { + _footnote_definition_end(context, input, starting_bracket_depth) } +} + +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn _footnote_definition_end<'r, 's>( + _context: Context<'r, 's>, + input: OrgSource<'s>, + starting_bracket_depth: isize, +) -> Res, OrgSource<'s>> { + let current_depth = input.get_bracket_depth() - starting_bracket_depth; if current_depth > 0 { // Its impossible for the next character to end the footnote reference definition if we're any amount of brackets deep return Err(nom::Err::Error(CustomError::MyError(MyError( "NoFootnoteReferenceDefinitionEnd".into(), )))); } + if current_depth < 0 { + // This shouldn't be possible because if depth is 0 then a closing bracket should end the footnote definition. + unreachable!("Exceeded footnote reference definition bracket depth.") + } tag("]")(input) } - -#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn get_bracket_depth<'r, 's>( - context: Context<'r, 's>, -) -> Option<&'r FootnoteReferenceDefinition<'s>> { - for node in context.iter() { - match node.get_data() { - ContextElement::FootnoteReferenceDefinition(depth) => return Some(depth), - _ => {} - } - } - None -} diff --git a/src/parser/parser_context.rs b/src/parser/parser_context.rs index 22fa9281..034d8642 100644 --- a/src/parser/parser_context.rs +++ b/src/parser/parser_context.rs @@ -124,18 +124,6 @@ pub enum ContextElement<'r, 's> { /// radio links matching the contents of radio targets. RadioTarget(Vec<&'r Vec>>), - /// Stores the current bracket depth inside a footnote reference's definition. - /// - /// The definition inside a footnote reference must have balanced - /// brackets [] inside the definition, so this stores the amount - /// of opening brackets subtracted by the amount of closing - /// brackets within the definition must equal zero. - /// - /// A reference to the position in the string is also included so - /// unbalanced brackets can be detected in the middle of an - /// object. - FootnoteReferenceDefinition(FootnoteReferenceDefinition<'s>), - /// Stores the current bracket depth inside a citation. /// /// The global prefix, global suffix, key prefix, and key suffix @@ -195,12 +183,6 @@ pub struct ExitMatcherNode<'r> { pub class: ExitClass, } -#[derive(Debug)] -pub struct FootnoteReferenceDefinition<'s> { - pub position: OrgSource<'s>, - pub depth: usize, -} - #[derive(Debug)] pub struct CitationBracket<'s> { pub position: OrgSource<'s>,