2022-12-11 02:07:12 -05:00
use std ::rc ::Rc ;
2022-12-15 23:09:40 -05:00
use super ::error ::CustomError ;
2022-12-15 23:15:27 -05:00
use super ::error ::MyError ;
2022-12-18 03:04:18 -05:00
use super ::error ::Res ;
2022-12-03 22:18:37 -05:00
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 ;
2023-04-18 20:33:01 -04:00
use crate ::parser ::exiting ::ExitClass ;
use nom ::combinator ::eof ;
use nom ::IResult ;
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 > ;
2022-11-24 16:01:52 -05:00
2022-12-03 22:18:37 -05:00
#[ derive(Debug, Clone) ]
2022-12-10 23:49:02 -05:00
pub struct ContextTree < ' r , ' s > {
tree : List < ContextElement < ' r , ' s > > ,
2022-11-24 15:40:07 -05:00
}
2022-12-10 23:49:02 -05:00
impl < ' r , ' s > ContextTree < ' r , ' s > {
2022-11-26 22:03:15 -05:00
pub fn new ( ) -> Self {
2022-12-03 22:18:37 -05:00
ContextTree { tree : List ::new ( ) }
2022-11-24 15:40:07 -05:00
}
2022-11-24 16:01:52 -05:00
2023-04-10 10:49:28 -04:00
pub fn branch_from ( trunk : & Rc < Node < ContextElement < ' r , ' s > > > ) -> Self {
ContextTree {
2023-04-12 11:17:21 -04:00
tree : List ::branch_from ( trunk ) ,
2023-04-10 10:49:28 -04:00
}
}
2022-12-10 23:49:02 -05:00
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 )
}
2022-12-10 23:49:02 -05:00
pub fn with_additional_node ( & self , data : ContextElement < ' r , ' s > ) -> ContextTree < ' r , ' s > {
2022-12-03 22:18:37 -05:00
let new_list = self . tree . push_front ( data ) ;
ContextTree { tree : new_list }
}
2022-12-10 23:49:02 -05:00
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-10 22:20:29 -05:00
}
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 )
}
2022-12-16 00:47:33 -05:00
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 )
}
2023-03-27 18:22:08 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
2022-12-15 21:24:53 -05:00
pub fn check_exit_matcher (
2022-12-03 22:18:37 -05:00
& ' 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 > > {
2023-03-25 14:45:35 -04:00
// 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.
2023-04-12 11:17:21 -04:00
let at_end_of_file = eof ( i ) ;
2023-03-25 14:45:35 -04:00
if at_end_of_file . is_ok ( ) {
return at_end_of_file ;
}
2023-03-31 13:22:30 -04:00
// let blocked_context =
// self.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
// exit_matcher: ChainBehavior::IgnoreParent(Some(&always_fail)),
// }));
2023-03-27 18:08:17 -04:00
2023-04-18 20:33:01 -04:00
let mut current_class_filter = ExitClass ::Beta ;
2022-12-15 21:30:53 -05:00
for current_node in self . iter ( ) {
let context_element = current_node . get_data ( ) ;
2022-12-03 22:18:37 -05:00
match context_element {
2022-12-15 21:24:53 -05:00
ContextElement ::ExitMatcherNode ( exit_matcher ) = > {
2023-04-18 20:33:01 -04:00
if exit_matcher . class as u32 < = current_class_filter as u32 {
current_class_filter = exit_matcher . class ;
let local_context = ContextTree ::branch_from ( current_node ) ;
let local_result = ( exit_matcher . exit_matcher ) ( & local_context , i ) ;
if local_result . is_ok ( ) {
return local_result ;
2022-12-03 22:18:37 -05:00
}
2023-04-18 20:33:01 -04:00
}
2022-12-03 22:18:37 -05:00
}
2023-03-23 14:13:21 -04:00
_ = > { }
2022-12-03 22:18:37 -05:00
} ;
2022-11-26 22:03:15 -05:00
}
2022-12-15 23:15:27 -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
}
2023-04-10 10:36:16 -04:00
/// 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
}
2022-11-26 22:36:02 -05:00
}
2022-12-03 23:57:39 -05:00
#[ derive(Debug) ]
2022-12-10 23:49:02 -05:00
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.
2023-03-23 16:40:39 -04:00
DocumentRoot ( & ' s str ) ,
2023-04-10 10:36:16 -04:00
/// 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
2023-04-10 10:36:16 -04:00
/// Stores the indentation level of the current list item.
2023-03-17 16:49:09 -04:00
ListItem ( usize ) ,
2023-04-03 18:33:07 -04:00
2023-04-10 10:36:16 -04:00
/// Stores the name of the greater block.
2023-04-03 18:33:07 -04:00
GreaterBlock ( & ' s str ) ,
2023-04-10 10:36:16 -04:00
/// Indicates if elements should consume the whitespace after them.
ConsumeTrailingWhitespace ( bool ) ,
2022-11-26 22:54:54 -05:00
}
2022-12-15 21:24:53 -05:00
pub struct ExitMatcherNode < ' r > {
2023-04-18 20:33:01 -04:00
pub exit_matcher : & ' r Matcher ,
pub class : ExitClass ,
2022-11-26 22:36:02 -05:00
}
2022-11-26 22:54:54 -05:00
#[ derive(Clone) ]
2022-11-26 22:36:02 -05:00
pub enum ChainBehavior < ' r > {
AndParent ( Option < & ' r Matcher > ) ,
IgnoreParent ( Option < & ' r Matcher > ) ,
}
2023-04-18 20:33:01 -04:00
impl < ' r > std ::fmt ::Debug for ExitMatcherNode < ' r > {
2022-11-25 18:23:51 -05:00
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
2023-04-18 20:33:01 -04:00
let mut formatter = f . debug_struct ( " ExitMatcherNode " ) ;
2022-12-03 22:18:37 -05:00
// 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
}
}