2023-07-24 15:41:14 -04:00
use nom ::branch ::alt ;
use nom ::bytes ::complete ::tag ;
use nom ::character ::complete ::anychar ;
use nom ::character ::complete ::one_of ;
use nom ::combinator ::map ;
use nom ::combinator ::not ;
use nom ::combinator ::opt ;
use nom ::combinator ::peek ;
use nom ::combinator ::recognize ;
use nom ::combinator ::verify ;
use nom ::multi ::many_till ;
2023-08-29 11:18:15 -04:00
use super ::org_source ::BracketDepth ;
2023-08-23 00:30:26 -04:00
use super ::org_source ::OrgSource ;
2023-08-31 15:44:44 -04:00
use super ::util ::maybe_consume_object_trailing_whitespace_if_not_exiting ;
2023-07-24 14:19:19 -04:00
use super ::Context ;
2023-07-24 15:41:14 -04:00
use super ::Object ;
use crate ::error ::CustomError ;
use crate ::error ::MyError ;
2023-07-24 14:19:19 -04:00
use crate ::error ::Res ;
2023-07-24 15:41:14 -04:00
use crate ::parser ::util ::get_consumed ;
2023-07-24 14:19:19 -04:00
use crate ::parser ::Subscript ;
use crate ::parser ::Superscript ;
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 00:30:26 -04:00
pub fn subscript < ' r , ' s > (
2023-09-02 22:45:46 -04:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Subscript < ' s > > {
2023-07-24 15:41:14 -04:00
// We check for the underscore first before checking the pre-character as a minor optimization to avoid walking up the context tree to find the document root unnecessarily.
let ( remaining , _ ) = tag ( " _ " ) ( input ) ? ;
pre ( context , input ) ? ;
let ( remaining , _body ) = script_body ( context , remaining ) ? ;
2023-08-31 15:44:44 -04:00
let ( remaining , _trailing_whitespace ) =
maybe_consume_object_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-07-24 15:41:14 -04:00
let source = get_consumed ( input , remaining ) ;
2023-08-23 00:30:26 -04:00
Ok ( (
remaining ,
Subscript {
source : source . into ( ) ,
} ,
) )
2023-07-24 14:19:19 -04:00
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-24 14:19:19 -04:00
pub fn superscript < ' r , ' s > (
2023-09-02 22:45:46 -04:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Superscript < ' s > > {
2023-07-24 15:41:14 -04:00
// We check for the circumflex first before checking the pre-character as a minor optimization to avoid walking up the context tree to find the document root unnecessarily.
let ( remaining , _ ) = tag ( " ^ " ) ( input ) ? ;
pre ( context , input ) ? ;
let ( remaining , _body ) = script_body ( context , remaining ) ? ;
2023-08-31 15:44:44 -04:00
let ( remaining , _trailing_whitespace ) =
maybe_consume_object_trailing_whitespace_if_not_exiting ( context , remaining ) ? ;
2023-07-24 15:41:14 -04:00
let source = get_consumed ( input , remaining ) ;
2023-08-23 00:30:26 -04:00
Ok ( (
remaining ,
Superscript {
source : source . into ( ) ,
} ,
) )
2023-07-24 15:41:14 -04:00
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-09-02 22:45:46 -04:00
fn pre < ' r , ' s > ( _context : RefContext < '_ , ' r , ' s > , input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , ( ) > {
2023-08-24 16:55:56 -04:00
let preceding_character = input . get_preceding_character ( ) ;
2023-07-24 15:41:14 -04:00
match preceding_character {
Some ( c ) if ! c . is_whitespace ( ) = > { }
_ = > {
return Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
2023-08-23 00:30:26 -04:00
" Must be preceded by a non-whitespace character. " . into ( ) ,
2023-07-24 15:41:14 -04:00
) ) ) ) ;
}
} ;
Ok ( ( input , ( ) ) )
}
#[ derive(Debug) ]
enum ScriptBody < ' s > {
Braceless ( & ' s str ) ,
WithBraces ( Vec < Object < ' s > > ) ,
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 00:30:26 -04:00
fn script_body < ' r , ' s > (
2023-09-02 22:45:46 -04:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , ScriptBody < ' s > > {
2023-07-24 15:41:14 -04:00
alt ( (
map ( parser_with_context! ( script_asterisk ) ( context ) , | body | {
2023-08-23 00:30:26 -04:00
ScriptBody ::Braceless ( body . into ( ) )
2023-07-24 15:41:14 -04:00
} ) ,
map ( parser_with_context! ( script_alphanum ) ( context ) , | body | {
2023-08-23 00:30:26 -04:00
ScriptBody ::Braceless ( body . into ( ) )
2023-07-24 15:41:14 -04:00
} ) ,
2023-07-24 16:29:31 -04:00
map ( parser_with_context! ( script_with_braces ) ( context ) , | body | {
2023-08-23 00:30:26 -04:00
ScriptBody ::WithBraces ( body . into ( ) )
2023-07-24 16:29:31 -04:00
} ) ,
2023-07-24 15:41:14 -04:00
) ) ( input )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 00:30:26 -04:00
fn script_asterisk < ' r , ' s > (
2023-09-02 22:45:46 -04:00
_context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-07-24 15:41:14 -04:00
tag ( " * " ) ( input )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-23 00:30:26 -04:00
fn script_alphanum < ' r , ' s > (
2023-09-02 22:45:46 -04:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-07-24 15:41:14 -04:00
let ( remaining , _sign ) = opt ( recognize ( one_of ( " +- " ) ) ) ( input ) ? ;
let ( remaining , _script ) = many_till (
parser_with_context! ( script_alphanum_character ) ( context ) ,
parser_with_context! ( end_script_alphanum_character ) ( context ) ,
) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-24 15:41:14 -04:00
fn script_alphanum_character < ' r , ' s > (
2023-09-02 22:45:46 -04:00
_context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-07-24 15:41:14 -04:00
recognize ( verify ( anychar , | c | {
c . is_alphanumeric ( ) | | r # ",.\"# . contains ( * c )
} ) ) ( input )
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-24 15:41:14 -04:00
fn end_script_alphanum_character < ' r , ' s > (
2023-09-02 22:45:46 -04:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-07-24 15:41:14 -04:00
let ( remaining , final_char ) = recognize ( verify ( anychar , | c | c . is_alphanumeric ( ) ) ) ( input ) ? ;
peek ( not ( parser_with_context! ( script_alphanum_character ) (
context ,
) ) ) ( remaining ) ? ;
Ok ( ( remaining , final_char ) )
2023-07-24 14:19:19 -04:00
}
2023-07-24 16:29:31 -04:00
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-07-24 16:29:31 -04:00
fn script_with_braces < ' r , ' s > (
2023-09-02 22:45:46 -04:00
context : RefContext < '_ , ' r , ' s > ,
2023-08-23 00:30:26 -04:00
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , Vec < Object < ' s > > > {
2023-07-24 16:29:31 -04:00
let ( remaining , _ ) = tag ( " { " ) ( input ) ? ;
2023-08-28 02:37:01 -04:00
let exit_with_depth = script_with_braces_end ( remaining . get_brace_depth ( ) ) ;
let parser_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
2023-08-24 23:34:23 -04:00
class : ExitClass ::Gamma ,
2023-08-28 02:37:01 -04:00
exit_matcher : & exit_with_depth ,
2023-07-24 16:29:31 -04:00
} ) ) ;
let ( remaining , ( children , _exit_contents ) ) = many_till (
parser_with_context! ( standard_set_object ) ( & parser_context ) ,
parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ,
) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " } " ) ( remaining ) ? ;
Ok ( ( remaining , children ) )
}
2023-08-28 02:37:01 -04:00
fn script_with_braces_end (
2023-08-29 11:18:15 -04:00
starting_brace_depth : BracketDepth ,
2023-08-28 02:37:01 -04:00
) -> 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 )
2023-07-24 16:29:31 -04:00
}
}
2023-08-10 20:04:59 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-08-28 02:37:01 -04:00
fn _script_with_braces_end < ' r , ' s > (
2023-09-02 22:45:46 -04:00
_context : RefContext < '_ , ' r , ' s > ,
2023-08-28 02:37:01 -04:00
input : OrgSource < ' s > ,
2023-08-29 11:18:15 -04:00
starting_brace_depth : BracketDepth ,
2023-08-28 02:37:01 -04:00
) -> 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 ( ) ,
) ) ) ) ;
}
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. " )
2023-07-24 16:29:31 -04:00
}
2023-08-28 02:37:01 -04:00
tag ( " } " ) ( input )
2023-07-24 16:29:31 -04:00
}