Implement generic function for balanced brackets text.

This commit is contained in:
Tom Alexander 2023-10-05 19:19:27 -04:00
parent efac73798f
commit 885fefd060
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -15,10 +15,14 @@ use nom::sequence::tuple;
use nom::InputTake; use nom::InputTake;
use super::keyword::affiliated_keyword; use super::keyword::affiliated_keyword;
use super::org_source::BracketDepth;
use super::util::get_name; use super::util::get_name;
use super::util::start_of_line; use super::util::start_of_line;
use super::OrgSource; use super::OrgSource;
use crate::context::Matcher;
use crate::context::RefContext; use crate::context::RefContext;
use crate::error::CustomError;
use crate::error::MyError;
use crate::error::Res; use crate::error::Res;
use crate::parser::util::get_consumed; use crate::parser::util::get_consumed;
use crate::parser::util::org_line_ending; use crate::parser::util::org_line_ending;
@ -125,20 +129,37 @@ fn inside_header<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>>
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn arguments<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> { fn arguments<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
let (remaining, _) = tag("(")(input)?; balanced_bracket(
|i| tag("(")(i),
|i| peek(tag(")"))(i),
|i| recognize(tuple((space0, org_line_ending)))(i),
|i| tag(")")(i),
|s| s.get_parenthesis_depth(),
)(input)
let (remaining, contents) = opt(verify( // impl_balanced_bracket(
recognize(many_till( // input,
anychar, // |i| tag("(")(i),
alt(( // |i| peek(tag(")"))(i),
peek(recognize(one_of(")"))), // |i| recognize(tuple((space0, org_line_ending)))(i),
recognize(tuple((space0, org_line_ending))), // |i| tag(")")(i),
)), // |s| s.get_parenthesis_depth(),
)), // )
|s| s.len() > 0,
))(remaining)?; // let (remaining, _) = tag("(")(input)?;
let (remaining, _) = tag(")")(remaining)?;
Ok((remaining, contents)) // let (remaining, contents) = opt(verify(
// recognize(many_till(
// anychar,
// alt((
// peek(recognize(one_of(")"))),
// recognize(tuple((space0, org_line_ending))),
// )),
// )),
// |s| s.len() > 0,
// ))(remaining)?;
// let (remaining, _) = tag(")")(remaining)?;
// Ok((remaining, contents))
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
@ -150,6 +171,80 @@ fn end_header<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
)(remaining) )(remaining)
} }
fn balanced_bracket<
O: Matcher,
S: Matcher,
F: Matcher,
E: Matcher,
D: for<'ss> Fn(OrgSource<'ss>) -> BracketDepth,
>(
opening_parser: O,
stop_parser: S,
fail_parser: F,
end_parser: E,
depth_function: D,
) -> impl for<'s> Fn(OrgSource<'s>) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
move |input| {
impl_balanced_bracket::<&O, &S, &F, &E, &D>(
input,
&opening_parser,
&stop_parser,
&fail_parser,
&end_parser,
&depth_function,
)
}
}
fn impl_balanced_bracket<
's,
O: Matcher,
S: Matcher,
F: Matcher,
E: Matcher,
D: for<'ss> Fn(OrgSource<'ss>) -> BracketDepth,
>(
input: OrgSource<'s>,
opening_parser: O,
stop_parser: S,
fail_parser: F,
end_parser: E,
depth_function: D,
) -> Res<OrgSource<'s>, Option<OrgSource<'s>>> {
let (mut remaining, _) = opening_parser(input)?;
let contents_start = remaining;
let original_depth = depth_function(remaining);
loop {
let bracket_depth = depth_function(remaining);
if bracket_depth == original_depth {
let (remain, stop_result) = opt(&stop_parser)(remaining)?;
remaining = remain;
if stop_result.is_some() {
break;
}
}
if fail_parser(remaining).is_ok() {
return Err(nom::Err::Error(CustomError::MyError(MyError(
"Fail parser matched.",
))));
}
let (remain, _) = anychar(remaining)?;
remaining = remain;
}
let contents_end = remaining;
let (remaining, _) = end_parser(remaining)?;
let contents = if contents_start != contents_end {
Some(contents_start.get_until(contents_end))
} else {
None
};
Ok((remaining, contents))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use nom::combinator::opt; use nom::combinator::opt;