Create a start_of_line parser.

This commit is contained in:
Tom Alexander 2023-03-24 16:37:34 -04:00
parent ceb7788cfa
commit 754c1922df
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -99,6 +99,29 @@ fn headline<'r, 's>(
context: Context<'r, 's>, context: Context<'r, 's>,
input: &'s str, input: &'s str,
) -> Res<&'s str, (usize, &'s str, Vec<Object<'s>>, &'s str)> { ) -> Res<&'s str, (usize, &'s str, Vec<Object<'s>>, &'s str)> {
let parser_context =
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
exit_matcher: ChainBehavior::AndParent(Some(&headline_end)),
}));
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
let start_of_line_matcher = parser_with_context!(start_of_line)(&parser_context);
let (remaining, (_sol, star_count, ws, title, ws2)) = tuple((
start_of_line_matcher,
many1_count(tag("*")),
space1,
many1(standard_set_object_matcher),
alt((line_ending, eof)),
))(input)?;
Ok((remaining, (star_count, ws, title, ws2)))
}
fn headline_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
line_ending(input)
}
/// Check that we are at the start of a line
fn start_of_line<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, ()> {
let document_root = context.get_document_root().unwrap(); let document_root = context.get_document_root().unwrap();
let preceding_character = get_one_before(document_root, input) let preceding_character = get_one_before(document_root, input)
.map(|slice| slice.chars().next()) .map(|slice| slice.chars().next())
@ -108,32 +131,16 @@ fn headline<'r, 's>(
Some(_) => { Some(_) => {
// Not at start of line, cannot be a heading // Not at start of line, cannot be a heading
return Err(nom::Err::Error(CustomError::MyError(MyError( return Err(nom::Err::Error(CustomError::MyError(MyError(
"Heading not at start of line", "Not at start of line",
)))); ))));
} }
// If None, we are at the start of the file which allows for headings // If None, we are at the start of the file which allows for headings
None => {} None => {}
}; };
Ok((input, ()))
let parser_context =
context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
exit_matcher: ChainBehavior::AndParent(Some(&headline_end)),
}));
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
let ret = tuple((
many1_count(tag("*")),
space1,
many1(standard_set_object_matcher),
alt((line_ending, eof)),
))(input);
ret
}
fn headline_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
line_ending(input)
} }
/// Get one character from before the current position.
fn get_one_before<'s>(document: &'s str, current_position: &'s str) -> Option<&'s str> { fn get_one_before<'s>(document: &'s str, current_position: &'s str) -> Option<&'s str> {
assert!(is_slice_of(document, current_position)); assert!(is_slice_of(document, current_position));
if document.as_ptr() as usize == current_position.as_ptr() as usize { if document.as_ptr() as usize == current_position.as_ptr() as usize {
@ -144,6 +151,7 @@ fn get_one_before<'s>(document: &'s str, current_position: &'s str) -> Option<&'
Some(&document[previous_character_offset..offset]) Some(&document[previous_character_offset..offset])
} }
/// Check if the child string slice is a slice of the parent string slice.
fn is_slice_of(parent: &str, child: &str) -> bool { fn is_slice_of(parent: &str, child: &str) -> bool {
let parent_start = parent.as_ptr() as usize; let parent_start = parent.as_ptr() as usize;
let parent_end = parent_start + parent.len(); let parent_end = parent_start + parent.len();