diff --git a/src/parser/inline_babel_call.rs b/src/parser/inline_babel_call.rs index a1ed4e36..baa6008b 100644 --- a/src/parser/inline_babel_call.rs +++ b/src/parser/inline_babel_call.rs @@ -12,9 +12,10 @@ use nom::multi::many_till; 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::BabelHeaderBracket; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ExitMatcherNode; use crate::parser::parser_with_context::parser_with_context; @@ -74,14 +75,11 @@ fn header<'r, 's>( ) -> Res, OrgSource<'s>> { let (remaining, _) = tag("[")(input)?; - let parser_context = context - .with_additional_node(ContextElement::BabelHeaderBracket(BabelHeaderBracket { - 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::Gamma, - exit_matcher: &header_end, + exit_matcher: &exit_with_depth, })); let (remaining, name) = recognize(many_till( @@ -92,28 +90,30 @@ fn header<'r, 's>( Ok((remaining, name)) } +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) + } +} + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn header_end<'r, 's>( - context: Context<'r, 's>, +fn _header_end<'r, 's>( + _context: Context<'r, 's>, input: OrgSource<'s>, + starting_bracket_depth: isize, ) -> Res, OrgSource<'s>> { - let context_depth = get_bracket_depth(context) - .expect("This function should only be called from inside an inline babel call 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 babel call header bracket depth.") - } - ')' if current_depth > 0 => { - current_depth -= 1; - } - _ => {} - } + 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) } @@ -125,14 +125,11 @@ fn argument<'r, 's>( ) -> Res, OrgSource<'s>> { let (remaining, _) = tag("(")(input)?; - let parser_context = context - .with_additional_node(ContextElement::BabelHeaderBracket(BabelHeaderBracket { - position: remaining, - depth: 0, - })) - .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + let exit_with_depth = argument_end(remaining.get_parenthesis_depth()); + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Gamma, - exit_matcher: &argument_end, + exit_matcher: &exit_with_depth, })); let (remaining, name) = recognize(many_till( @@ -143,39 +140,30 @@ fn argument<'r, 's>( Ok((remaining, name)) } -#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] -fn argument_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 babel call argument."); - 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 babel call argument bracket depth.") - } - ']' if current_depth > 0 => { - current_depth -= 1; - } - _ => {} - } +fn argument_end( + starting_parenthesis_depth: isize, +) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res, OrgSource<'s>> { + move |context: Context, input: OrgSource<'_>| { + _argument_end(context, input, starting_parenthesis_depth) } - alt((tag(")"), 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 BabelHeaderBracket<'s>> { - for node in context.iter() { - match node.get_data() { - ContextElement::BabelHeaderBracket(depth) => return Some(depth), - _ => {} - } +fn _argument_end<'r, 's>( + _context: Context<'r, 's>, + input: OrgSource<'s>, + starting_parenthesis_depth: isize, +) -> Res, OrgSource<'s>> { + let current_depth = input.get_parenthesis_depth() - starting_parenthesis_depth; + if current_depth > 0 { + // Its impossible for the next character to end the argument if we're any amount of parenthesis deep + return Err(nom::Err::Error(CustomError::MyError(MyError( + "NoArgumentEnd".into(), + )))); } - None + if current_depth < 0 { + // This shouldn't be possible because if depth is 0 then a closing parenthesis should end the argument. + unreachable!("Exceeded argument parenthesis depth.") + } + alt((tag(")"), line_ending))(input) } diff --git a/src/parser/parser_context.rs b/src/parser/parser_context.rs index db7312f2..770f871c 100644 --- a/src/parser/parser_context.rs +++ b/src/parser/parser_context.rs @@ -124,19 +124,6 @@ pub enum ContextElement<'r, 's> { /// 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. - BabelHeaderBracket(BabelHeaderBracket<'s>), - /// Stores the current bracket or parenthesis depth inside an inline babel call. /// /// Inside an inline babel call the headers must have balanced @@ -156,12 +143,6 @@ pub struct ExitMatcherNode<'r> { pub class: ExitClass, } -#[derive(Debug)] -pub struct BabelHeaderBracket<'s> { - pub position: OrgSource<'s>, - pub depth: usize, -} - #[derive(Debug)] pub struct InlineSourceBlockBracket<'s> { pub position: OrgSource<'s>,