2023-07-24 15:41:14 -04:00
use nom ::branch ::alt ;
use nom ::bytes ::complete ::tag ;
2023-09-07 03:40:14 -04:00
use nom ::bytes ::complete ::take_while ;
2023-07-24 15:41:14 -04:00
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-09-07 03:40:14 -04:00
use nom ::sequence ::tuple ;
2023-07-24 15:41:14 -04:00
2023-09-03 00:27:50 -04:00
use super ::object_parser ::standard_set_object ;
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-09-03 00:27:50 -04:00
use super ::util ::exit_matcher_parser ;
2023-08-31 15:44:44 -04:00
use super ::util ::maybe_consume_object_trailing_whitespace_if_not_exiting ;
2023-09-07 02:27:55 -04:00
use super ::util ::preceded_by_whitespace ;
2023-09-03 00:27:50 -04:00
use crate ::context ::parser_with_context ;
use crate ::context ::ContextElement ;
2023-09-03 15:44:18 -04:00
use crate ::context ::ContextMatcher ;
2023-09-03 00:27:50 -04:00
use crate ::context ::ExitClass ;
use crate ::context ::ExitMatcherNode ;
2023-09-21 19:21:47 -04:00
use crate ::context ::Matcher ;
2023-09-03 00:27:50 -04:00
use crate ::context ::RefContext ;
2023-07-24 15:41:14 -04:00
use crate ::error ::CustomError ;
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-09-03 00:27:50 -04:00
use crate ::types ::Object ;
2023-10-09 19:51:31 -04:00
use crate ::types ::PlainText ;
2023-09-03 00:27:50 -04:00
use crate ::types ::Subscript ;
use crate ::types ::Superscript ;
2023-07-24 14:19:19 -04:00
2023-09-07 02:59:08 -04:00
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
2023-09-11 13:13:28 -04:00
pub ( crate ) fn detect_subscript_or_superscript < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , ( ) > {
2023-09-07 02:59:08 -04:00
// This does not have to detect all valid subscript/superscript but all that it detects must be valid.
let ( remaining , _ ) = one_of ( " _^ " ) ( input ) ? ;
pre ( input ) ? ;
if tag ::< _ , _ , CustomError < _ > > ( " * " ) ( remaining ) . is_ok ( ) {
return Ok ( ( input , ( ) ) ) ;
}
let ( remaining , _ ) = opt ( one_of ( " +- " ) ) ( remaining ) ? ;
let ( _remaining , _ ) = verify ( anychar , | c | c . is_alphanumeric ( ) ) ( remaining ) ? ;
Ok ( ( input , ( ) ) )
}
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( context ) )
) ]
2023-09-11 13:13:28 -04:00
pub ( crate ) fn subscript < ' b , ' g , ' r , ' s > (
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' 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 ) ? ;
2023-09-07 02:27:55 -04:00
pre ( input ) ? ;
2023-10-09 19:51:31 -04:00
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-10-09 19:51:31 -04:00
let ( use_brackets , body ) = match body {
ScriptBody ::Braceless ( text ) = > ( false , vec! [ Object ::PlainText ( PlainText { source : text } ) ] ) ,
ScriptBody ::WithBraces ( body ) = > ( true , body ) ,
} ;
2023-08-23 00:30:26 -04:00
Ok ( (
remaining ,
Subscript {
source : source . into ( ) ,
2023-10-09 19:51:31 -04:00
use_brackets ,
children : body ,
2023-08-23 00:30:26 -04:00
} ,
) )
2023-07-24 14:19:19 -04:00
}
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( context ) )
) ]
2023-09-11 13:13:28 -04:00
pub ( crate ) fn superscript < ' b , ' g , ' r , ' s > (
2023-09-03 15:44:18 -04:00
context : RefContext < ' b , ' g , ' 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 ) ? ;
2023-09-07 02:27:55 -04:00
pre ( input ) ? ;
2023-10-09 19:51:31 -04:00
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-10-09 19:51:31 -04:00
let ( use_brackets , body ) = match body {
ScriptBody ::Braceless ( text ) = > ( false , vec! [ Object ::PlainText ( PlainText { source : text } ) ] ) ,
ScriptBody ::WithBraces ( body ) = > ( true , body ) ,
} ;
2023-08-23 00:30:26 -04:00
Ok ( (
remaining ,
Superscript {
source : source . into ( ) ,
2023-10-09 19:51:31 -04:00
use_brackets ,
children : body ,
2023-08-23 00:30:26 -04:00
} ,
) )
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-07 02:27:55 -04:00
fn pre < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , ( ) > {
not ( preceded_by_whitespace ( true ) ) ( input ) ? ;
2023-07-24 15:41:14 -04:00
Ok ( ( input , ( ) ) )
}
#[ derive(Debug) ]
enum ScriptBody < ' s > {
Braceless ( & ' s str ) ,
WithBraces ( Vec < Object < ' s > > ) ,
}
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( context ) )
) ]
2023-09-03 15:44:18 -04:00
fn script_body < ' b , ' g , ' r , ' s > (
context : RefContext < ' b , ' g , ' 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-10-16 17:14:44 -04:00
ScriptBody ::WithBraces ( body )
2023-07-24 16:29:31 -04:00
} ) ,
2023-09-21 19:21:47 -04:00
map (
parser_with_context! ( script_with_parenthesis ) ( context ) ,
| body | ScriptBody ::Braceless ( body . into ( ) ) ,
) ,
2023-07-24 15:41:14 -04:00
) ) ( input )
}
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( _context ) )
) ]
2023-09-03 15:44:18 -04:00
fn script_asterisk < ' b , ' g , ' r , ' s > (
_context : RefContext < ' b , ' g , ' 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-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( _context ) )
) ]
2023-09-03 15:44:18 -04:00
fn script_alphanum < ' b , ' g , ' r , ' s > (
2023-09-07 02:27:55 -04:00
_context : RefContext < ' b , ' g , ' 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 ) ? ;
2023-09-07 02:27:55 -04:00
let ( remaining , _script ) =
many_till ( script_alphanum_character , end_script_alphanum_character ) ( remaining ) ? ;
2023-07-24 15:41:14 -04:00
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-09-07 02:27:55 -04:00
fn script_alphanum_character < ' s > ( input : OrgSource < ' s > ) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
2023-07-24 15:41:14 -04:00
recognize ( verify ( anychar , | c | {
2023-10-16 19:43:15 -04:00
c . is_alphanumeric ( ) | | r ",.\" . contains ( * c )
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-09-07 02:27:55 -04:00
fn end_script_alphanum_character < ' s > ( 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 ) ? ;
2023-09-07 03:40:14 -04:00
peek ( tuple ( (
2023-10-16 19:43:15 -04:00
take_while ( | c | r ",.\" . contains ( c ) ) ,
2023-09-07 03:40:14 -04:00
not ( script_alphanum_character ) ,
) ) ) ( remaining ) ? ;
2023-07-24 15:41:14 -04:00
Ok ( ( remaining , final_char ) )
2023-07-24 14:19:19 -04:00
}
2023-07-24 16:29:31 -04:00
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( context ) )
) ]
2023-09-03 15:44:18 -04:00
fn script_with_braces < ' b , ' g , ' r , ' s > (
context : RefContext < ' b , ' g , ' 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 ( ) ) ;
2023-09-03 00:27:50 -04:00
let parser_context = ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Gamma ,
exit_matcher : & exit_with_depth ,
} ) ;
let parser_context = context . with_additional_node ( & parser_context ) ;
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-09-03 15:44:18 -04:00
fn script_with_braces_end ( starting_brace_depth : BracketDepth ) -> impl ContextMatcher {
2023-09-03 00:27:50 -04:00
move | context , input : OrgSource < '_ > | {
2023-08-28 02:37:01 -04:00
_script_with_braces_end ( context , input , starting_brace_depth )
2023-07-24 16:29:31 -04:00
}
}
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( _context ) )
) ]
2023-09-03 15:44:18 -04:00
fn _script_with_braces_end < ' b , ' g , ' r , ' s > (
_context : RefContext < ' b , ' g , ' 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 (
2023-10-16 17:03:16 -04:00
" Not a valid end for subscript or superscript. " ,
2023-08-28 02:37:01 -04:00
) ) ) ) ;
}
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
}
2023-09-21 19:21:47 -04:00
2023-10-09 18:00:48 -04:00
#[ cfg_attr(
feature = " tracing " ,
tracing ::instrument ( ret , level = " debug " , skip ( context ) )
) ]
2023-09-21 19:21:47 -04:00
fn script_with_parenthesis < ' b , ' g , ' r , ' s > (
context : RefContext < ' b , ' g , ' r , ' s > ,
input : OrgSource < ' s > ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
let ( remaining , _ ) = tag ( " ( " ) ( input ) ? ;
let exit_with_depth = script_with_parenthesis_end ( remaining . get_parenthesis_depth ( ) ) ;
let ( remaining , _ ) = many_till (
anychar ,
alt ( (
peek ( exit_with_depth ) ,
parser_with_context! ( exit_matcher_parser ) ( context ) ,
) ) ,
) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " ) " ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
fn script_with_parenthesis_end ( starting_parenthesis_depth : BracketDepth ) -> impl Matcher {
move | input : OrgSource < '_ > | _script_with_parenthesis_end ( input , starting_parenthesis_depth )
}
#[ cfg_attr(feature = " tracing " , tracing::instrument(ret, level = " debug " )) ]
fn _script_with_parenthesis_end < ' s > (
input : OrgSource < ' s > ,
starting_parenthesis_depth : BracketDepth ,
) -> Res < OrgSource < ' s > , OrgSource < ' s > > {
let current_depth = input . get_parenthesis_depth ( ) - starting_parenthesis_depth ;
if current_depth < 0 {
// This shouldn't be possible because if depth is 0 then a closing bracket should end the citation.
unreachable! ( " Exceeded citation key suffix bracket depth. " )
}
if current_depth = = 0 {
let close_parenthesis = tag ::< & str , OrgSource < '_ > , CustomError < OrgSource < '_ > > > ( " ) " ) ( input ) ;
if close_parenthesis . is_ok ( ) {
return close_parenthesis ;
}
}
Err ( nom ::Err ::Error ( CustomError ::MyError ( MyError (
2023-10-16 17:03:16 -04:00
" No script parenthesis end. " ,
2023-09-21 19:21:47 -04:00
) ) ) )
}