Compare commits
10 Commits
20c17c40be
...
288350daef
Author | SHA1 | Date | |
---|---|---|---|
![]() |
288350daef | ||
![]() |
c683516620 | ||
![]() |
e731e8ff6b | ||
![]() |
4c2037ec44 | ||
![]() |
a46b358549 | ||
![]() |
ec813e3b3f | ||
![]() |
f11f7bcc73 | ||
![]() |
9e0e5f6f0a | ||
![]() |
16e788c36c | ||
![]() |
1952d175c0 |
22
org_mode_samples/object/citation/balanced_brackets.org
Normal file
22
org_mode_samples/object/citation/balanced_brackets.org
Normal file
@ -0,0 +1,22 @@
|
||||
# Extra open
|
||||
[cite/a/b-_/foo:unbalancedglobal[prefix;keyprefix @foo keysuffix;globalsuffix]
|
||||
|
||||
[cite/a/b-_/foo:globalprefix;unbalancedkey[prefix @foo keysuffix;globalsuffix]
|
||||
|
||||
[cite/a/b-_/foo:globalprefix;keyprefix @foo unbalancedkey[suffix;globalsuffix]
|
||||
|
||||
[cite/a/b-_/foo:globalprefix;keyprefix @foo keysuffix;unbalancedglobal[suffix]
|
||||
|
||||
|
||||
# Extra close
|
||||
[cite/a/b-_/foo:unbalancedglobal]prefix;keyprefix @foo keysuffix;globalsuffix]
|
||||
|
||||
[cite/a/b-_/foo:globalprefix;unbalancedkey]prefix @foo keysuffix;globalsuffix]
|
||||
|
||||
[cite/a/b-_/foo:globalprefix;keyprefix @foo unbalancedkey]suffix;globalsuffix]
|
||||
|
||||
[cite/a/b-_/foo:globalprefix;keyprefix @foo keysuffix;unbalancedglobal]suffix]
|
||||
|
||||
|
||||
# balanced:
|
||||
[cite/a/b-_/foo:gl[obalpref]ix;ke[ypref]ix @foo ke[ysuff]ix;gl[obalsuff]ix]
|
@ -0,0 +1,2 @@
|
||||
[fn:2:This footnote [ has balanced ] brackets inside it]
|
||||
[fn::This footnote does not have balanced [ brackets inside it]
|
6
org_mode_samples/object/latex_fragment/three_lines.org
Normal file
6
org_mode_samples/object/latex_fragment/three_lines.org
Normal file
@ -0,0 +1,6 @@
|
||||
$foo
|
||||
bar
|
||||
baz
|
||||
lorem
|
||||
ipsum
|
||||
dolar$
|
17
org_mode_samples/object/text_markup/three_lines.org
Normal file
17
org_mode_samples/object/text_markup/three_lines.org
Normal file
@ -0,0 +1,17 @@
|
||||
foo *bar
|
||||
baz* lorem
|
||||
|
||||
text *markup
|
||||
can
|
||||
span* more
|
||||
|
||||
than *three
|
||||
lines.
|
||||
foo
|
||||
bar* baz
|
||||
|
||||
foo *bar \\
|
||||
baz \\
|
||||
lorem \\
|
||||
ipsum \\
|
||||
dolar* cat
|
@ -11,17 +11,16 @@ use nom::multi::many_till;
|
||||
use nom::multi::separated_list1;
|
||||
use nom::sequence::tuple;
|
||||
|
||||
use super::citation_reference::must_balance_bracket;
|
||||
use super::org_source::OrgSource;
|
||||
use super::Context;
|
||||
use crate::error::CustomError;
|
||||
use crate::error::Res;
|
||||
use crate::parser::citation_reference::citation_reference;
|
||||
use crate::parser::citation_reference::citation_reference_key;
|
||||
use crate::parser::citation_reference::get_bracket_depth;
|
||||
use crate::parser::exiting::ExitClass;
|
||||
use crate::parser::object::Citation;
|
||||
use crate::parser::object_parser::standard_set_object;
|
||||
use crate::parser::parser_context::CitationBracket;
|
||||
use crate::parser::parser_context::ContextElement;
|
||||
use crate::parser::parser_context::ExitMatcherNode;
|
||||
use crate::parser::parser_with_context::parser_with_context;
|
||||
@ -38,13 +37,15 @@ pub fn citation<'r, 's>(
|
||||
let (remaining, _) = tag_no_case("[cite")(input)?;
|
||||
let (remaining, _) = opt(citestyle)(remaining)?;
|
||||
let (remaining, _) = tag(":")(remaining)?;
|
||||
let (remaining, _prefix) = opt(parser_with_context!(global_prefix)(context))(remaining)?;
|
||||
let (remaining, _prefix) =
|
||||
must_balance_bracket(opt(parser_with_context!(global_prefix)(context)))(remaining)?;
|
||||
|
||||
let (remaining, _references) =
|
||||
separated_list1(tag(";"), parser_with_context!(citation_reference)(context))(remaining)?;
|
||||
let (remaining, _suffix) = opt(tuple((
|
||||
let (remaining, _suffix) = must_balance_bracket(opt(tuple((
|
||||
tag(";"),
|
||||
parser_with_context!(global_suffix)(context),
|
||||
)))(remaining)?;
|
||||
))))(remaining)?;
|
||||
let (remaining, _) = tag("]")(remaining)?;
|
||||
let (remaining, _) = space0(remaining)?;
|
||||
let source = get_consumed(input, remaining);
|
||||
@ -83,15 +84,11 @@ fn global_prefix<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||
// TODO: I could insert CitationBracket entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient.
|
||||
let parser_context = context
|
||||
.with_additional_node(ContextElement::CitationBracket(CitationBracket {
|
||||
position: input,
|
||||
depth: 0,
|
||||
}))
|
||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
let exit_with_depth = global_prefix_end(input.get_bracket_depth());
|
||||
let parser_context =
|
||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: &global_prefix_end,
|
||||
exit_matcher: &exit_with_depth,
|
||||
}));
|
||||
let (remaining, (children, _exit_contents)) = verify(
|
||||
many_till(
|
||||
@ -104,28 +101,24 @@ fn global_prefix<'r, 's>(
|
||||
Ok((remaining, children))
|
||||
}
|
||||
|
||||
fn global_prefix_end(
|
||||
starting_bracket_depth: isize,
|
||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
move |context: Context, input: OrgSource<'_>| {
|
||||
_global_prefix_end(context, input, starting_bracket_depth)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn global_prefix_end<'r, 's>(
|
||||
fn _global_prefix_end<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
starting_bracket_depth: isize,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let context_depth = get_bracket_depth(context)
|
||||
.expect("This function should only be called from inside a citation.");
|
||||
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 citation global prefix bracket depth.")
|
||||
}
|
||||
']' if current_depth > 0 => {
|
||||
current_depth -= 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let current_depth = input.get_bracket_depth() - starting_bracket_depth;
|
||||
if current_depth < 0 {
|
||||
// This shouldn't be possible because if depth is 0 then a closing bracket should end the citation.
|
||||
unreachable!("Exceeded citation global prefix bracket depth.")
|
||||
}
|
||||
if current_depth == 0 {
|
||||
let close_bracket = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>("]")(input);
|
||||
@ -144,15 +137,11 @@ fn global_suffix<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||
// TODO: I could insert CitationBracket entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient.
|
||||
let parser_context = context
|
||||
.with_additional_node(ContextElement::CitationBracket(CitationBracket {
|
||||
position: input,
|
||||
depth: 0,
|
||||
}))
|
||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
let exit_with_depth = global_suffix_end(input.get_bracket_depth());
|
||||
let parser_context =
|
||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: &global_suffix_end,
|
||||
exit_matcher: &exit_with_depth,
|
||||
}));
|
||||
let (remaining, (children, _exit_contents)) = verify(
|
||||
many_till(
|
||||
@ -164,28 +153,24 @@ fn global_suffix<'r, 's>(
|
||||
Ok((remaining, children))
|
||||
}
|
||||
|
||||
fn global_suffix_end(
|
||||
starting_bracket_depth: isize,
|
||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
move |context: Context, input: OrgSource<'_>| {
|
||||
_global_suffix_end(context, input, starting_bracket_depth)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn global_suffix_end<'r, 's>(
|
||||
fn _global_suffix_end<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
starting_bracket_depth: isize,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let context_depth = get_bracket_depth(context)
|
||||
.expect("This function should only be called from inside a citation.");
|
||||
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 citation global suffix bracket depth.")
|
||||
}
|
||||
']' if current_depth > 0 => {
|
||||
current_depth -= 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let current_depth = input.get_bracket_depth() - starting_bracket_depth;
|
||||
if current_depth < 0 {
|
||||
// This shouldn't be possible because if depth is 0 then a closing bracket should end the citation.
|
||||
unreachable!("Exceeded citation global suffix bracket depth.")
|
||||
}
|
||||
if current_depth == 0 {
|
||||
let close_bracket = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>("]")(input);
|
||||
|
@ -13,11 +13,11 @@ use nom::sequence::tuple;
|
||||
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::object::CitationReference;
|
||||
use crate::parser::object_parser::minimal_set_object;
|
||||
use crate::parser::parser_context::CitationBracket;
|
||||
use crate::parser::parser_context::ContextElement;
|
||||
use crate::parser::parser_context::ExitMatcherNode;
|
||||
use crate::parser::parser_with_context::parser_with_context;
|
||||
@ -31,9 +31,11 @@ pub fn citation_reference<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, CitationReference<'s>> {
|
||||
let (remaining, _prefix) = opt(parser_with_context!(key_prefix)(context))(input)?;
|
||||
let (remaining, _prefix) =
|
||||
must_balance_bracket(opt(parser_with_context!(key_prefix)(context)))(input)?;
|
||||
let (remaining, _key) = parser_with_context!(citation_reference_key)(context)(remaining)?;
|
||||
let (remaining, _suffix) = opt(parser_with_context!(key_suffix)(context))(remaining)?;
|
||||
let (remaining, _suffix) =
|
||||
must_balance_bracket(opt(parser_with_context!(key_suffix)(context)))(remaining)?;
|
||||
let source = get_consumed(input, remaining);
|
||||
|
||||
Ok((
|
||||
@ -69,15 +71,11 @@ fn key_prefix<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||
// TODO: I could insert CitationBracket entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient.
|
||||
let parser_context = context
|
||||
.with_additional_node(ContextElement::CitationBracket(CitationBracket {
|
||||
position: input,
|
||||
depth: 0,
|
||||
}))
|
||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
let exit_with_depth = key_prefix_end(input.get_bracket_depth());
|
||||
let parser_context =
|
||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: &key_prefix_end,
|
||||
exit_matcher: &exit_with_depth,
|
||||
}));
|
||||
let (remaining, (children, _exit_contents)) = verify(
|
||||
many_till(
|
||||
@ -94,15 +92,11 @@ fn key_suffix<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||
// TODO: I could insert CitationBracket entries in the context after each matched object to reduce the scanning done for counting brackets which should be more efficient.
|
||||
let parser_context = context
|
||||
.with_additional_node(ContextElement::CitationBracket(CitationBracket {
|
||||
position: input,
|
||||
depth: 0,
|
||||
}))
|
||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
let exit_with_depth = key_suffix_end(input.get_bracket_depth());
|
||||
let parser_context =
|
||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: &key_suffix_end,
|
||||
exit_matcher: &exit_with_depth,
|
||||
}));
|
||||
let (remaining, (children, _exit_contents)) = verify(
|
||||
many_till(
|
||||
@ -114,39 +108,24 @@ fn key_suffix<'r, 's>(
|
||||
Ok((remaining, children))
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
pub fn get_bracket_depth<'r, 's>(context: Context<'r, 's>) -> Option<&'r CitationBracket<'s>> {
|
||||
for node in context.iter() {
|
||||
match node.get_data() {
|
||||
ContextElement::CitationBracket(depth) => return Some(depth),
|
||||
_ => {}
|
||||
}
|
||||
fn key_prefix_end(
|
||||
starting_bracket_depth: isize,
|
||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
move |context: Context, input: OrgSource<'_>| {
|
||||
_key_prefix_end(context, input, starting_bracket_depth)
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn key_prefix_end<'r, 's>(
|
||||
fn _key_prefix_end<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
starting_bracket_depth: isize,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let context_depth = get_bracket_depth(context)
|
||||
.expect("This function should only be called from inside a citation reference.");
|
||||
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 citation reference key prefix bracket depth.")
|
||||
}
|
||||
']' if current_depth > 0 => {
|
||||
current_depth -= 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let current_depth = input.get_bracket_depth() - starting_bracket_depth;
|
||||
if current_depth < 0 {
|
||||
// This shouldn't be possible because if depth is 0 then a closing bracket should end the citation.
|
||||
unreachable!("Exceeded citation key prefix bracket depth.")
|
||||
}
|
||||
if current_depth == 0 {
|
||||
let close_bracket = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>("]")(input);
|
||||
@ -160,28 +139,24 @@ fn key_prefix_end<'r, 's>(
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn key_suffix_end(
|
||||
starting_bracket_depth: isize,
|
||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
move |context: Context, input: OrgSource<'_>| {
|
||||
_key_suffix_end(context, input, starting_bracket_depth)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn key_suffix_end<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
fn _key_suffix_end<'r, 's>(
|
||||
_context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
starting_bracket_depth: isize,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let context_depth = get_bracket_depth(context)
|
||||
.expect("This function should only be called from inside a citation reference.");
|
||||
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 citation reference key prefix bracket depth.")
|
||||
}
|
||||
']' if current_depth > 0 => {
|
||||
current_depth -= 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let current_depth = input.get_bracket_depth() - starting_bracket_depth;
|
||||
if current_depth < 0 {
|
||||
// This shouldn't be possible because if depth is 0 then a closing bracket should end the citation.
|
||||
unreachable!("Exceeded citation key suffix bracket depth.")
|
||||
}
|
||||
if current_depth == 0 {
|
||||
let close_bracket = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>("]")(input);
|
||||
@ -191,3 +166,21 @@ fn key_suffix_end<'r, 's>(
|
||||
}
|
||||
tag(";")(input)
|
||||
}
|
||||
|
||||
pub fn must_balance_bracket<'s, F, O>(
|
||||
mut inner: F,
|
||||
) -> impl FnMut(OrgSource<'s>) -> Res<OrgSource<'s>, O>
|
||||
where
|
||||
F: FnMut(OrgSource<'s>) -> Res<OrgSource<'s>, O>,
|
||||
{
|
||||
move |input: OrgSource<'_>| {
|
||||
let pre_bracket_depth = input.get_bracket_depth();
|
||||
let (remaining, output) = inner(input)?;
|
||||
if remaining.get_bracket_depth() - pre_bracket_depth != 0 {
|
||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||
"UnbalancedBrackets".into(),
|
||||
))));
|
||||
}
|
||||
Ok((remaining, output))
|
||||
}
|
||||
}
|
||||
|
@ -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<OrgSource<'s>, 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>, 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>, 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>, 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
|
||||
}
|
||||
|
@ -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>, 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>, 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>, 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>, 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>, 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>, 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>, 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)
|
||||
}
|
||||
|
@ -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>, 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>, 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<OrgSource<'_>>>("]")(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>, 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>, 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>, 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>, 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>, 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<OrgSource<'_>>>("}")(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)
|
||||
}
|
||||
|
@ -202,17 +202,13 @@ fn bordered_dollar_fragment<'r, 's>(
|
||||
// TODO: I'm assuming I should be peeking at the borders but the documentation is not clear. Test to figure out.
|
||||
let (_, _) = peek(parser_with_context!(open_border)(context))(remaining)?;
|
||||
|
||||
// TODO: As an optimization it would be nice to exit early upon hitting the 3rd line break
|
||||
let (remaining, _) = verify(
|
||||
recognize(many_till(
|
||||
anychar,
|
||||
peek(alt((
|
||||
parser_with_context!(exit_matcher_parser)(context),
|
||||
tag("$"),
|
||||
))),
|
||||
)),
|
||||
|body: &OrgSource<'_>| Into::<&str>::into(body).lines().take(4).count() <= 3,
|
||||
)(remaining)?;
|
||||
let (remaining, _) = recognize(many_till(
|
||||
anychar,
|
||||
peek(alt((
|
||||
parser_with_context!(exit_matcher_parser)(context),
|
||||
tag("$"),
|
||||
))),
|
||||
))(remaining)?;
|
||||
|
||||
let (_, _) = peek(parser_with_context!(close_border)(context))(remaining)?;
|
||||
let (remaining, _) = tag("$")(remaining)?;
|
||||
|
@ -18,6 +18,10 @@ pub struct OrgSource<'s> {
|
||||
end: usize, // exclusive
|
||||
start_of_line: usize,
|
||||
preceding_character: Option<char>,
|
||||
line_number: usize,
|
||||
bracket_depth: isize, // []
|
||||
brace_depth: isize, // {}
|
||||
parenthesis_depth: isize, // ()
|
||||
}
|
||||
|
||||
impl<'s> OrgSource<'s> {
|
||||
@ -31,6 +35,10 @@ impl<'s> OrgSource<'s> {
|
||||
end: input.len(),
|
||||
start_of_line: 0,
|
||||
preceding_character: None,
|
||||
line_number: 1,
|
||||
bracket_depth: 0,
|
||||
brace_depth: 0,
|
||||
parenthesis_depth: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +64,22 @@ impl<'s> OrgSource<'s> {
|
||||
assert!(other.end <= self.end);
|
||||
self.slice(..(other.start - self.start))
|
||||
}
|
||||
|
||||
pub fn get_line_number(&self) -> usize {
|
||||
self.line_number
|
||||
}
|
||||
|
||||
pub fn get_bracket_depth(&self) -> isize {
|
||||
self.bracket_depth
|
||||
}
|
||||
|
||||
pub fn get_brace_depth(&self) -> isize {
|
||||
self.brace_depth
|
||||
}
|
||||
|
||||
pub fn get_parenthesis_depth(&self) -> isize {
|
||||
self.parenthesis_depth
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> InputTake for OrgSource<'s> {
|
||||
@ -119,10 +143,38 @@ where
|
||||
}
|
||||
|
||||
let skipped_text = &self.full_source[self.start..new_start];
|
||||
let start_of_line = skipped_text
|
||||
.rfind('\n')
|
||||
.map(|idx| self.start + idx + 1)
|
||||
.unwrap_or(self.start_of_line);
|
||||
let mut start_of_line = self.start_of_line;
|
||||
let mut line_number = self.line_number;
|
||||
let mut bracket_depth = self.bracket_depth;
|
||||
let mut brace_depth = self.brace_depth;
|
||||
let mut parenthesis_depth = self.parenthesis_depth;
|
||||
for (offset, byte) in skipped_text.bytes().enumerate() {
|
||||
match byte {
|
||||
b'\n' => {
|
||||
start_of_line = self.start + offset + 1;
|
||||
line_number += 1;
|
||||
}
|
||||
b'[' => {
|
||||
bracket_depth += 1;
|
||||
}
|
||||
b']' => {
|
||||
bracket_depth -= 1;
|
||||
}
|
||||
b'{' => {
|
||||
brace_depth += 1;
|
||||
}
|
||||
b'}' => {
|
||||
brace_depth -= 1;
|
||||
}
|
||||
b'(' => {
|
||||
parenthesis_depth += 1;
|
||||
}
|
||||
b')' => {
|
||||
parenthesis_depth -= 1;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
OrgSource {
|
||||
full_source: self.full_source,
|
||||
@ -130,6 +182,10 @@ where
|
||||
end: new_end,
|
||||
start_of_line,
|
||||
preceding_character: skipped_text.chars().last(),
|
||||
line_number,
|
||||
bracket_depth,
|
||||
brace_depth,
|
||||
parenthesis_depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -369,4 +425,28 @@ mod tests {
|
||||
assert_eq!(input.get_preceding_character(), None);
|
||||
assert_eq!(input.slice(8..).get_preceding_character(), Some('💛'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_number() {
|
||||
let input = OrgSource::new("lorem\nfoo\nbar\nbaz\nipsum");
|
||||
assert_eq!(input.get_line_number(), 1);
|
||||
assert_eq!(input.slice(5..).get_line_number(), 1);
|
||||
assert_eq!(input.slice(6..).get_line_number(), 2);
|
||||
assert_eq!(input.slice(6..).slice(10..).get_line_number(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn depth() {
|
||||
let input = OrgSource::new("[][()][({)]}}}}");
|
||||
assert_eq!(input.get_bracket_depth(), 0);
|
||||
assert_eq!(input.get_brace_depth(), 0);
|
||||
assert_eq!(input.get_parenthesis_depth(), 0);
|
||||
assert_eq!(input.slice(4..).get_bracket_depth(), 1);
|
||||
assert_eq!(input.slice(4..).get_brace_depth(), 0);
|
||||
assert_eq!(input.slice(4..).get_parenthesis_depth(), 1);
|
||||
assert_eq!(input.slice(4..).slice(6..).get_bracket_depth(), 1);
|
||||
assert_eq!(input.slice(4..).slice(6..).get_brace_depth(), 1);
|
||||
assert_eq!(input.slice(4..).slice(6..).get_parenthesis_depth(), 0);
|
||||
assert_eq!(input.slice(14..).get_brace_depth(), -2);
|
||||
}
|
||||
}
|
||||
|
@ -123,71 +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<Object<'s>>>),
|
||||
|
||||
/// 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
|
||||
/// 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. None of the prefixes or
|
||||
/// suffixes can be nested inside each other so we can use a
|
||||
/// single type for this without conflict.
|
||||
///
|
||||
/// A reference to the position in the string is also included so
|
||||
/// unbalanced brackets can be detected in the middle of an
|
||||
/// object.
|
||||
CitationBracket(CitationBracket<'s>),
|
||||
|
||||
/// 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
|
||||
/// 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>),
|
||||
|
||||
/// Stores the current bracket or parenthesis depth inside a
|
||||
/// superscript or superscript.
|
||||
///
|
||||
/// Inside the braces of a subscript or superscript there must be
|
||||
/// balanced braces {}, so this stores the amount of opening
|
||||
/// braces subtracted by the amount of closing braces within the
|
||||
/// definition must equal zero.
|
||||
///
|
||||
/// A reference to the position in the string is also included so
|
||||
/// unbalanced braces can be detected in the middle of an object.
|
||||
SubscriptSuperscriptBrace(SubscriptSuperscriptBrace<'s>),
|
||||
}
|
||||
|
||||
pub struct ExitMatcherNode<'r> {
|
||||
@ -195,36 +130,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>,
|
||||
pub depth: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BabelHeaderBracket<'s> {
|
||||
pub position: OrgSource<'s>,
|
||||
pub depth: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InlineSourceBlockBracket<'s> {
|
||||
pub position: OrgSource<'s>,
|
||||
pub depth: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SubscriptSuperscriptBrace<'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");
|
||||
|
@ -21,7 +21,6 @@ use crate::parser::exiting::ExitClass;
|
||||
use crate::parser::object_parser::standard_set_object;
|
||||
use crate::parser::parser_context::ContextElement;
|
||||
use crate::parser::parser_context::ExitMatcherNode;
|
||||
use crate::parser::parser_context::SubscriptSuperscriptBrace;
|
||||
use crate::parser::parser_with_context::parser_with_context;
|
||||
use crate::parser::util::exit_matcher_parser;
|
||||
use crate::parser::util::get_consumed;
|
||||
@ -154,16 +153,11 @@ fn script_with_braces<'r, 's>(
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Vec<Object<'s>>> {
|
||||
let (remaining, _) = tag("{")(input)?;
|
||||
let parser_context = context
|
||||
.with_additional_node(ContextElement::SubscriptSuperscriptBrace(
|
||||
SubscriptSuperscriptBrace {
|
||||
position: remaining.into(),
|
||||
depth: 0,
|
||||
},
|
||||
))
|
||||
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
let exit_with_depth = script_with_braces_end(remaining.get_brace_depth());
|
||||
let parser_context =
|
||||
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: &script_with_braces_end,
|
||||
exit_matcher: &exit_with_depth,
|
||||
}));
|
||||
|
||||
let (remaining, (children, _exit_contents)) = many_till(
|
||||
@ -175,49 +169,30 @@ fn script_with_braces<'r, 's>(
|
||||
Ok((remaining, children))
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn script_with_braces_end<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let context_depth = get_bracket_depth(context)
|
||||
.expect("This function should only be called from inside a subscript or superscript.");
|
||||
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 subscript or superscript brace depth.")
|
||||
}
|
||||
'}' if current_depth > 0 => {
|
||||
current_depth -= 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
fn script_with_braces_end(
|
||||
starting_brace_depth: isize,
|
||||
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
move |context: Context, input: OrgSource<'_>| {
|
||||
_script_with_braces_end(context, input, starting_brace_depth)
|
||||
}
|
||||
if current_depth == 0 {
|
||||
let close_bracket = tag::<&str, OrgSource<'_>, CustomError<OrgSource<'_>>>("}")(input);
|
||||
if close_bracket.is_ok() {
|
||||
return close_bracket;
|
||||
}
|
||||
}
|
||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||
"Not a valid end for subscript or superscript.".into(),
|
||||
))));
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn get_bracket_depth<'r, 's>(
|
||||
context: Context<'r, 's>,
|
||||
) -> Option<&'r SubscriptSuperscriptBrace<'s>> {
|
||||
for node in context.iter() {
|
||||
match node.get_data() {
|
||||
ContextElement::SubscriptSuperscriptBrace(depth) => return Some(depth),
|
||||
_ => {}
|
||||
}
|
||||
fn _script_with_braces_end<'r, 's>(
|
||||
_context: Context<'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
starting_brace_depth: isize,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let current_depth = input.get_brace_depth() - starting_brace_depth;
|
||||
if current_depth > 0 {
|
||||
// Its impossible for the next character to end the subscript or superscript if we're any amount of braces deep
|
||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||
"Not a valid end for subscript or superscript.".into(),
|
||||
))));
|
||||
}
|
||||
None
|
||||
if current_depth < 0 {
|
||||
// This shouldn't be possible because if depth is 0 then a closing brace should end the subscript or superscript.
|
||||
unreachable!("Exceeded subscript or superscript brace depth.")
|
||||
}
|
||||
tag("}")(input)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user