diff --git a/src/parser/inline_source_block.rs b/src/parser/inline_source_block.rs index f25be84..b1e893a 100644 --- a/src/parser/inline_source_block.rs +++ b/src/parser/inline_source_block.rs @@ -1,3 +1,4 @@ +use nom::branch::alt; use nom::bytes::complete::tag; use nom::bytes::complete::tag_no_case; use nom::character::complete::anychar; @@ -14,11 +15,11 @@ use tracing::span; use super::org_source::OrgSource; use super::Context; use crate::error::CustomError; +use crate::error::MyError; use crate::error::Res; use crate::parser::exiting::ExitClass; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ExitMatcherNode; -use crate::parser::parser_context::InlineSourceBlockBracket; use crate::parser::parser_with_context::parser_with_context; use crate::parser::util::exit_matcher_parser; use crate::parser::util::get_consumed; @@ -75,16 +76,11 @@ fn header<'r, 's>( ) -> Res, OrgSource<'s>> { let (remaining, _) = tag("[")(input)?; - let parser_context = context - .with_additional_node(ContextElement::InlineSourceBlockBracket( - InlineSourceBlockBracket { - position: remaining, - depth: 0, - }, - )) - .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + let exit_with_depth = header_end(remaining.get_bracket_depth()); + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Beta, - exit_matcher: &header_end, + exit_matcher: &exit_with_depth, })); let (remaining, header_contents) = recognize(many_till( @@ -95,37 +91,32 @@ fn header<'r, 's>( Ok((remaining, header_contents)) } -#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn header_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 an inline source block header."); - 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 inline source block header bracket depth.") - } - ']' if current_depth > 0 => { - current_depth -= 1; - } - _ => {} - } - } - if current_depth == 0 { - let close_bracket = tag::<&str, OrgSource<'_>, CustomError>>("]")(input); - if close_bracket.is_ok() { - return close_bracket; - } +fn header_end( + starting_bracket_depth: isize, +) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res, OrgSource<'s>> { + move |context: Context, input: OrgSource<'_>| { + _header_end(context, input, starting_bracket_depth) } +} - line_ending(input) +#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] +fn _header_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 header if we're any amount of bracket deep + return Err(nom::Err::Error(CustomError::MyError(MyError( + "NoHeaderEnd".into(), + )))); + } + if current_depth < 0 { + // This shouldn't be possible because if depth is 0 then a closing bracket should end the header. + unreachable!("Exceeded header bracket depth.") + } + alt((tag("]"), line_ending))(input) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] @@ -135,16 +126,11 @@ fn body<'r, 's>( ) -> Res, OrgSource<'s>> { let (remaining, _) = tag("{")(input)?; - let parser_context = context - .with_additional_node(ContextElement::InlineSourceBlockBracket( - InlineSourceBlockBracket { - position: remaining, - depth: 0, - }, - )) - .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + let exit_with_depth = body_end(remaining.get_brace_depth()); + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Beta, - exit_matcher: &body_end, + exit_matcher: &exit_with_depth, })); let (remaining, body_contents) = recognize(many_till( @@ -165,60 +151,28 @@ fn body<'r, 's>( Ok((remaining, body_contents)) } +fn body_end( + starting_brace_depth: isize, +) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res, OrgSource<'s>> { + move |context: Context, input: OrgSource<'_>| _body_end(context, input, starting_brace_depth) +} + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn body_end<'r, 's>( - context: Context<'r, 's>, +fn _body_end<'r, 's>( + _context: Context<'r, 's>, input: OrgSource<'s>, + starting_brace_depth: isize, ) -> Res, OrgSource<'s>> { - let context_depth = get_bracket_depth(context) - .expect("This function should only be called from inside an inline source block body."); - 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 inline source block body bracket depth.") - } - '}' if current_depth > 0 => { - current_depth -= 1; - } - _ => {} - } + let current_depth = input.get_brace_depth() - starting_brace_depth; + if current_depth > 0 { + // Its impossible for the next character to end the body if we're any amount of brace deep + return Err(nom::Err::Error(CustomError::MyError(MyError( + "NoBodyEnd".into(), + )))); } - { - #[cfg(feature = "tracing")] - let span = span!( - tracing::Level::DEBUG, - "inside end body", - remaining = Into::<&str>::into(input), - current_depth = current_depth - ); - #[cfg(feature = "tracing")] - let _enter = span.enter(); - - if current_depth == 0 { - let close_bracket = tag::<&str, OrgSource<'_>, CustomError>>("}")(input); - if close_bracket.is_ok() { - return close_bracket; - } - } + if current_depth < 0 { + // This shouldn't be possible because if depth is 0 then a closing brace should end the body. + unreachable!("Exceeded body brace depth.") } - - line_ending(input) -} - -#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -pub fn get_bracket_depth<'r, 's>( - context: Context<'r, 's>, -) -> Option<&'r InlineSourceBlockBracket<'s>> { - for node in context.iter() { - match node.get_data() { - ContextElement::InlineSourceBlockBracket(depth) => return Some(depth), - _ => {} - } - } - None + alt((tag("}"), line_ending))(input) } diff --git a/src/parser/parser_context.rs b/src/parser/parser_context.rs index 770f871..f4e72d5 100644 --- a/src/parser/parser_context.rs +++ b/src/parser/parser_context.rs @@ -123,19 +123,6 @@ 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 or parenthesis depth inside an inline babel call. - /// - /// Inside an inline babel call the headers must have balanced - /// parentheses () and the arguments must have balanced brackets - /// [], 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. - InlineSourceBlockBracket(InlineSourceBlockBracket<'s>), } pub struct ExitMatcherNode<'r> { @@ -143,12 +130,6 @@ pub struct ExitMatcherNode<'r> { pub class: ExitClass, } -#[derive(Debug)] -pub struct InlineSourceBlockBracket<'s> { - pub position: OrgSource<'s>, - 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");