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 0000000..251c9ad --- /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 ad35b9a..340e4c8 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 22fa928..034d864 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>,