Fix handling affiliated keywords before invalid paragraphs.
This commit is contained in:
parent
65eda08843
commit
1351577c5a
@ -12,6 +12,7 @@ use crate::error::CustomError;
|
||||
use crate::error::MyError;
|
||||
use crate::error::Res;
|
||||
use crate::parser::OrgSource;
|
||||
use crate::types::Keyword;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ContextElement<'r, 's> {
|
||||
@ -27,11 +28,22 @@ pub(crate) enum ContextElement<'r, 's> {
|
||||
/// Indicates if elements should consume the whitespace after them.
|
||||
ConsumeTrailingWhitespace(bool),
|
||||
|
||||
/// Indicate that we are parsing a paragraph that already has affiliated keywords.
|
||||
///
|
||||
/// The value stored is the start of the element after the affiliated keywords. In this way, we can ensure that we do not exit an element immediately after the affiliated keyword had been consumed.
|
||||
HasAffiliatedKeyword(HasAffiliatedKeywordInner<'r, 's>),
|
||||
|
||||
/// This is just here to use the 's lifetime until I'm sure we can eliminate it from ContextElement.
|
||||
#[allow(dead_code)]
|
||||
Placeholder(PhantomData<&'s str>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct HasAffiliatedKeywordInner<'r, 's> {
|
||||
pub(crate) start_after_affiliated_keywords: OrgSource<'s>,
|
||||
pub(crate) keywords: &'r Vec<Keyword<'s>>,
|
||||
}
|
||||
|
||||
pub(crate) struct ExitMatcherNode<'r> {
|
||||
// TODO: Should this be "&'r DynContextMatcher<'c>" ?
|
||||
pub(crate) exit_matcher: &'r DynContextMatcher<'r>,
|
||||
|
@ -21,6 +21,7 @@ type DynMatcher<'c> = dyn Matcher + 'c;
|
||||
pub(crate) use context::Context;
|
||||
pub(crate) use context::ContextElement;
|
||||
pub(crate) use context::ExitMatcherNode;
|
||||
pub(crate) use context::HasAffiliatedKeywordInner;
|
||||
pub(crate) use exiting::ExitClass;
|
||||
pub use file_access_interface::FileAccessInterface;
|
||||
pub use file_access_interface::LocalFileAccessInterface;
|
||||
|
@ -14,7 +14,7 @@ use crate::error::MyError;
|
||||
|
||||
pub(crate) type BracketDepth = i16;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub(crate) struct OrgSource<'s> {
|
||||
full_source: &'s str,
|
||||
start: usize,
|
||||
|
@ -12,12 +12,16 @@ use super::keyword::affiliated_keyword;
|
||||
use super::org_source::OrgSource;
|
||||
use super::util::blank_line;
|
||||
use super::util::get_consumed;
|
||||
use super::util::get_has_affiliated_keyword;
|
||||
use super::util::get_name;
|
||||
use crate::context::parser_with_context;
|
||||
use crate::context::ContextElement;
|
||||
use crate::context::ExitClass;
|
||||
use crate::context::ExitMatcherNode;
|
||||
use crate::context::HasAffiliatedKeywordInner;
|
||||
use crate::context::RefContext;
|
||||
use crate::error::CustomError;
|
||||
use crate::error::MyError;
|
||||
use crate::error::Res;
|
||||
use crate::parser::object_parser::standard_set_object;
|
||||
use crate::parser::util::exit_matcher_parser;
|
||||
@ -30,12 +34,18 @@ pub(crate) fn paragraph<'b, 'g, 'r, 's>(
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Paragraph<'s>> {
|
||||
let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?;
|
||||
|
||||
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: ¶graph_end,
|
||||
});
|
||||
let parser_context = context.with_additional_node(&parser_context);
|
||||
let contexts = [
|
||||
ContextElement::HasAffiliatedKeyword(HasAffiliatedKeywordInner {
|
||||
start_after_affiliated_keywords: input,
|
||||
keywords: &affiliated_keywords,
|
||||
}),
|
||||
ContextElement::ExitMatcherNode(ExitMatcherNode {
|
||||
class: ExitClass::Gamma,
|
||||
exit_matcher: ¶graph_end,
|
||||
}),
|
||||
];
|
||||
let parser_context = context.with_additional_node(&contexts[0]);
|
||||
let parser_context = parser_context.with_additional_node(&contexts[1]);
|
||||
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
|
||||
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
|
||||
|
||||
@ -63,10 +73,21 @@ fn paragraph_end<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
let non_paragraph_element_matcher = parser_with_context!(detect_element(false))(context);
|
||||
let regular_end = recognize(tuple((start_of_line, many1(blank_line))))(input);
|
||||
if regular_end.is_ok() {
|
||||
return regular_end;
|
||||
}
|
||||
match get_has_affiliated_keyword(context) {
|
||||
Some(start_post_affiliated_keywords) if input == start_post_affiliated_keywords => {
|
||||
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
||||
"No exit due to affiliated keywords.",
|
||||
))));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Check to see if input is the start of a HasAffiliatedKeyword
|
||||
alt((
|
||||
recognize(tuple((start_of_line, many1(blank_line)))),
|
||||
recognize(non_paragraph_element_matcher),
|
||||
recognize(parser_with_context!(detect_element(false))(context)),
|
||||
eof,
|
||||
))(input)
|
||||
}
|
||||
|
@ -284,3 +284,21 @@ pub(crate) fn get_name<'s>(affiliated_keywords: &Vec<Keyword<'s>>) -> Option<&'s
|
||||
.last();
|
||||
name_keyword.map(|kw| kw.value)
|
||||
}
|
||||
|
||||
pub(crate) fn get_has_affiliated_keyword<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
) -> Option<OrgSource<'s>> {
|
||||
for context in context.iter() {
|
||||
match context {
|
||||
ContextElement::HasAffiliatedKeyword(inner) => {
|
||||
if !inner.keywords.is_empty() {
|
||||
return Some(inner.start_after_affiliated_keywords);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user