From 5fb66a586d81215518eec95298d5664e87340431 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Jul 2023 20:52:09 -0400 Subject: [PATCH] Implement a function to detect the end of a footnote reference definition with balanced brackets. --- src/parser/footnote_definition.rs | 2 +- src/parser/footnote_reference.rs | 68 ++++++++++++++++++++++++++++++- src/parser/parser_context.rs | 18 ++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/parser/footnote_definition.rs b/src/parser/footnote_definition.rs index 833360e..61318dc 100644 --- a/src/parser/footnote_definition.rs +++ b/src/parser/footnote_definition.rs @@ -67,7 +67,7 @@ pub fn footnote_definition<'r, 's>( } #[tracing::instrument(ret, level = "debug")] -fn label<'s>(input: &'s str) -> Res<&'s str, &'s str> { +pub fn label<'s>(input: &'s str) -> Res<&'s str, &'s str> { alt(( digit1, take_while(|c| WORD_CONSTITUENT_CHARACTERS.contains(c) || "-_".contains(c)), diff --git a/src/parser/footnote_reference.rs b/src/parser/footnote_reference.rs index c43253b..6d88df0 100644 --- a/src/parser/footnote_reference.rs +++ b/src/parser/footnote_reference.rs @@ -1,13 +1,79 @@ +use nom::branch::alt; +use nom::bytes::complete::tag; +use nom::bytes::complete::tag_no_case; + +use super::parser_context::ContextElement; use super::Context; +use crate::error::CustomError; +use crate::error::MyError; use crate::error::Res; -use crate::parser::FootnoteReference; +use crate::parser::parser_context::FootnoteReferenceDefinition; +use crate::parser::parser_with_context::parser_with_context; +use crate::parser::util::get_consumed; use crate::parser::util::not_yet_implemented; +use crate::parser::FootnoteReference; +use crate::parser::Object; #[tracing::instrument(ret, level = "debug")] pub fn footnote_reference<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, FootnoteReference<'s>> { + alt((parser_with_context!(anonymous_footnote)(context),))(input) +} + +#[tracing::instrument(ret, level = "debug")] +pub fn anonymous_footnote<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, FootnoteReference<'s>> { + let (remaining, _) = tag_no_case("[fn::")(input)?; + not_yet_implemented()?; todo!() } + +#[tracing::instrument(ret, level = "debug")] +fn definition<'s>(input: &'s str) -> Res<&'s str, Vec>> { + Ok((input, vec![])) +} + +#[tracing::instrument(ret, level = "debug")] +fn footnote_definition_end<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, &'s str> { + 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 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; + }, + _ => {} + } + } + 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")))); + } + tag("]")(input) +} + +#[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 c49e099..d2c105e 100644 --- a/src/parser/parser_context.rs +++ b/src/parser/parser_context.rs @@ -141,6 +141,18 @@ pub enum ContextElement<'r, 's> { /// org-mode document since text needs to be re-parsed to look for /// 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. + /// + /// 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>), } pub struct ExitMatcherNode<'r> { @@ -148,6 +160,12 @@ pub struct ExitMatcherNode<'r> { pub class: ExitClass, } +#[derive(Debug)] +pub struct FootnoteReferenceDefinition<'s> { + pub position: &'s str, + pub depth: usize, +} + impl<'r> std::fmt::Debug for ExitMatcherNode<'r> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut formatter = f.debug_struct("ExitMatcherNode");