organic/src/parser/parser_context.rs

194 lines
6.5 KiB
Rust
Raw Normal View History

2022-12-11 02:07:12 -05:00
use std::rc::Rc;
use nom::combinator::eof;
use nom::IResult;
2022-11-24 14:59:37 -05:00
2022-12-15 23:09:40 -05:00
use super::error::CustomError;
use super::error::MyError;
2022-12-18 03:04:18 -05:00
use super::error::Res;
use super::list::List;
2022-12-11 02:07:12 -05:00
use super::list::Node;
2022-12-15 20:32:00 -05:00
use super::Context;
2022-11-24 15:40:07 -05:00
2022-12-18 03:04:18 -05:00
type Matcher = dyn for<'r, 's> Fn(Context<'r, 's>, &'s str) -> Res<&'s str, &'s str>;
#[derive(Debug, Clone)]
pub struct ContextTree<'r, 's> {
tree: List<ContextElement<'r, 's>>,
2022-11-24 15:40:07 -05:00
}
impl<'r, 's> ContextTree<'r, 's> {
2022-11-26 22:03:15 -05:00
pub fn new() -> Self {
ContextTree { tree: List::new() }
2022-11-24 15:40:07 -05:00
}
pub fn branch_from(trunk: &Rc<Node<ContextElement<'r, 's>>>) -> Self {
ContextTree {
tree: List::branch_from(trunk),
}
}
pub fn ptr_eq<'x, 'y>(&self, other: &ContextTree<'x, 'y>) -> bool {
2022-12-10 22:04:39 -05:00
self.tree.ptr_eq(&other.tree)
}
pub fn with_additional_node(&self, data: ContextElement<'r, 's>) -> ContextTree<'r, 's> {
let new_list = self.tree.push_front(data);
ContextTree { tree: new_list }
}
pub fn pop_front(&mut self) -> (Option<ContextElement<'r, 's>>, ContextTree<'r, 's>) {
2022-12-11 00:02:13 -05:00
let (popped_element, remaining) = self.tree.pop_front();
(popped_element, ContextTree { tree: remaining })
}
2022-12-11 02:07:12 -05:00
pub fn iter(&self) -> impl Iterator<Item = &Rc<Node<ContextElement<'r, 's>>>> {
self.tree.iter()
}
2022-12-15 23:52:52 -05:00
pub fn iter_until<'x: 'r>(
&'r self,
other: &'x ContextTree<'x, 's>,
) -> impl Iterator<Item = &Rc<Node<ContextElement<'r, 's>>>> {
self.tree.iter_until(&other.tree)
}
pub fn into_iter_until<'x: 'r>(
self,
other: &'x ContextTree<'x, 's>,
) -> impl Iterator<Item = ContextElement<'r, 's>> {
self.tree.into_iter_until(&other.tree)
}
#[tracing::instrument(ret, level = "debug")]
2022-12-15 21:24:53 -05:00
pub fn check_exit_matcher(
&'r self,
2022-12-15 20:32:00 -05:00
i: &'s str,
2022-12-15 23:09:40 -05:00
) -> IResult<&'s str, &'s str, CustomError<&'s str>> {
// Special check for EOF. We don't just make this a document-level exit matcher since the IgnoreParent ChainBehavior could cause early exit matchers to not run.
let at_end_of_file = eof(i);
if at_end_of_file.is_ok() {
return at_end_of_file;
}
// let blocked_context =
// self.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
// exit_matcher: ChainBehavior::IgnoreParent(Some(&always_fail)),
// }));
for current_node in self.iter() {
let context_element = current_node.get_data();
match context_element {
2022-12-15 21:24:53 -05:00
ContextElement::ExitMatcherNode(exit_matcher) => {
match exit_matcher.exit_matcher {
ChainBehavior::AndParent(Some(matcher)) => {
let local_context = ContextTree::branch_from(current_node);
let local_result = matcher(&local_context, i);
if local_result.is_ok() {
return local_result;
}
}
ChainBehavior::AndParent(None) => {}
ChainBehavior::IgnoreParent(Some(matcher)) => {
let local_context = ContextTree::branch_from(current_node);
let local_result = matcher(&local_context, i);
if local_result.is_ok() {
return local_result;
}
// TODO: Make this a specific error instead of just a generic MyError
return Err(nom::Err::Error(CustomError::MyError(MyError("NoExit"))));
}
ChainBehavior::IgnoreParent(None) => {
// TODO: Make this a specific error instead of just a generic MyError
return Err(nom::Err::Error(CustomError::MyError(MyError("NoExit"))));
}
};
}
2023-03-23 14:13:21 -04:00
_ => {}
};
2022-11-26 22:03:15 -05:00
}
// TODO: Make this a specific error instead of just a generic MyError
return Err(nom::Err::Error(CustomError::MyError(MyError("NoExit"))));
2022-11-26 22:03:15 -05:00
}
2023-03-23 19:35:32 -04:00
pub fn get_document_root(&self) -> Option<&'s str> {
for current_node in self.iter() {
let context_element = current_node.get_data();
match context_element {
ContextElement::DocumentRoot(body) => {
return Some(body);
}
_ => {}
}
}
None
}
/// Indicates if elements should consume the whitespace after them.
///
/// Defaults to true.
pub fn should_consume_trailing_whitespace(&self) -> bool {
self._should_consume_trailing_whitespace().unwrap_or(true)
}
fn _should_consume_trailing_whitespace(&self) -> Option<bool> {
for current_node in self.iter() {
let context_element = current_node.get_data();
match context_element {
ContextElement::ConsumeTrailingWhitespace(should) => {
return Some(*should);
}
_ => {}
}
}
None
}
}
#[derive(Debug)]
pub enum ContextElement<'r, 's> {
2023-03-25 14:10:22 -04:00
/// Stores a reference to the entire org-mode document being parsed.
///
/// This is used for look-behind.
DocumentRoot(&'s str),
/// Stores a parser that indicates that children should exit upon matching an exit matcher.
2022-12-15 21:24:53 -05:00
ExitMatcherNode(ExitMatcherNode<'r>),
2022-12-15 21:57:21 -05:00
Context(&'r str),
2023-03-25 14:10:22 -04:00
/// Stores the indentation level of the current list item.
ListItem(usize),
/// Stores the name of the greater block.
GreaterBlock(&'s str),
/// Indicates if elements should consume the whitespace after them.
ConsumeTrailingWhitespace(bool),
2022-11-26 22:54:54 -05:00
}
#[derive(Debug)]
2022-12-15 21:24:53 -05:00
pub struct ExitMatcherNode<'r> {
pub exit_matcher: ChainBehavior<'r>,
}
2022-11-26 22:54:54 -05:00
#[derive(Clone)]
pub enum ChainBehavior<'r> {
AndParent(Option<&'r Matcher>),
IgnoreParent(Option<&'r Matcher>),
}
impl<'r> std::fmt::Debug for ChainBehavior<'r> {
2022-11-25 18:23:51 -05:00
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut formatter = f.debug_struct("ChainBehavior");
// match self {
// ChainBehavior::AndParent(_) => {
// formatter = formatter.field("type", &"AndParent");
// }
// ChainBehavior::IgnoreParent(_) => {
// formatter = formatter.field("type", &"IgnoreParent");
// }
// };
formatter.finish()
2022-11-26 22:54:54 -05:00
}
}