2023-07-24 17:54:49 -04:00
use nom ::branch ::alt ;
2023-07-27 18:59:22 -04:00
use nom ::bytes ::complete ::tag ;
use nom ::character ::complete ::anychar ;
2023-07-27 19:20:28 -04:00
use nom ::character ::complete ::digit1 ;
2023-07-27 18:59:22 -04:00
use nom ::character ::complete ::one_of ;
use nom ::character ::complete ::space0 ;
2023-07-27 19:20:28 -04:00
use nom ::character ::complete ::space1 ;
use nom ::combinator ::opt ;
2023-07-27 18:59:22 -04:00
use nom ::combinator ::recognize ;
use nom ::combinator ::verify ;
use nom ::multi ::many_till ;
2023-07-27 19:20:28 -04:00
use nom ::sequence ::tuple ;
2023-07-24 17:54:49 -04:00
2023-07-24 17:34:07 -04:00
use super ::Context ;
use crate ::error ::Res ;
2023-07-27 18:59:22 -04:00
use crate ::parser ::exiting ::ExitClass ;
use crate ::parser ::parser_context ::ContextElement ;
use crate ::parser ::parser_context ::ExitMatcherNode ;
2023-07-24 17:54:49 -04:00
use crate ::parser ::parser_with_context ::parser_with_context ;
2023-07-27 18:59:22 -04:00
use crate ::parser ::util ::exit_matcher_parser ;
use crate ::parser ::util ::get_consumed ;
2023-07-24 17:34:07 -04:00
use crate ::parser ::util ::not_yet_implemented ;
use crate ::parser ::Timestamp ;
#[ tracing::instrument(ret, level = " debug " ) ]
pub fn timestamp < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-24 17:54:49 -04:00
// TODO: This would be more efficient if we didn't throw away the parse result of the first half of an active/inactive date range timestamp if the parse fails (as in, the first thing active_date_range_timestamp parses is a active_timestamp but then we throw that away if it doesn't turn out to be a full active_date_range_timestamp despite the active_timestamp parse being completely valid). I am going with the simplest/cleanest approach for the first implementation.
alt ( (
// Order matters here. If its a date range, we need to parse the entire date range instead of just the first timestamp. If its a time range, we need to make sure thats parsed as a time range instead of as the "rest" portion of a single timestamp.
parser_with_context! ( diary_timestamp ) ( context ) ,
parser_with_context! ( active_time_range_timestamp ) ( context ) ,
parser_with_context! ( inactive_time_range_timestamp ) ( context ) ,
parser_with_context! ( active_date_range_timestamp ) ( context ) ,
parser_with_context! ( inactive_date_range_timestamp ) ( context ) ,
parser_with_context! ( active_timestamp ) ( context ) ,
parser_with_context! ( inactive_timestamp ) ( context ) ,
) ) ( input )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn diary_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-27 18:59:22 -04:00
let ( remaining , _ ) = tag ( " <%%( " ) ( input ) ? ;
let ( remaining , _body ) = sexp ( context , remaining ) ? ;
let ( remaining , _ ) = tag ( " )> " ) ( remaining ) ? ;
let ( remaining , _ ) = space0 ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Timestamp { source } ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn sexp < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
let parser_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & sexp_end ,
} ) ) ;
let ( remaining , body ) = recognize ( verify (
many_till (
anychar ,
parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ,
) ,
| ( body , _end_contents ) | ! body . is_empty ( ) ,
) ) ( input ) ? ;
Ok ( ( remaining , body ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn sexp_end < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
alt ( ( tag ( " )> " ) , recognize ( one_of ( " > \n " ) ) ) ) ( input )
2023-07-24 17:54:49 -04:00
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn active_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-27 19:20:28 -04:00
let ( remaining , _ ) = tag ( " < " ) ( input ) ? ;
let ( remaining , _date ) = date ( context , remaining ) ? ;
2023-07-27 19:52:35 -04:00
let time_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & active_time_rest_end ,
} ) ) ;
2023-07-27 19:45:57 -04:00
let ( remaining , _time ) =
2023-07-27 19:52:35 -04:00
opt ( tuple ( ( space1 , parser_with_context! ( time ) ( & time_context ) ) ) ) ( remaining ) ? ;
2023-07-27 19:45:57 -04:00
let ( remaining , _repeater ) =
opt ( tuple ( ( space1 , parser_with_context! ( repeater ) ( context ) ) ) ) ( remaining ) ? ;
let ( remaining , _warning_delay ) = opt ( tuple ( (
space1 ,
parser_with_context! ( warning_delay ) ( context ) ,
) ) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " > " ) ( remaining ) ? ;
let ( remaining , _ ) = space0 ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Timestamp { source } ) )
2023-07-24 17:54:49 -04:00
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn inactive_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-27 19:54:33 -04:00
let ( remaining , _ ) = tag ( " [ " ) ( input ) ? ;
let ( remaining , _date ) = date ( context , remaining ) ? ;
let time_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & inactive_time_rest_end ,
} ) ) ;
let ( remaining , _time ) =
opt ( tuple ( ( space1 , parser_with_context! ( time ) ( & time_context ) ) ) ) ( remaining ) ? ;
let ( remaining , _repeater ) =
opt ( tuple ( ( space1 , parser_with_context! ( repeater ) ( context ) ) ) ) ( remaining ) ? ;
let ( remaining , _warning_delay ) = opt ( tuple ( (
space1 ,
parser_with_context! ( warning_delay ) ( context ) ,
) ) ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " ] " ) ( remaining ) ? ;
let ( remaining , _ ) = space0 ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Timestamp { source } ) )
2023-07-24 17:54:49 -04:00
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn active_date_range_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-27 19:59:36 -04:00
let ( remaining , _first_timestamp ) = active_timestamp ( context , input ) ? ;
// TODO: Does the space0 at the end of the active/inactive timestamp parsers cause this to be incorrect? I could use a look-behind to make sure the preceding character is not whitespace
let ( remaining , _separator ) = tag ( " -- " ) ( remaining ) ? ;
let ( remaining , _second_timestamp ) = active_timestamp ( context , remaining ) ? ;
let ( remaining , _ ) = space0 ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Timestamp { source } ) )
2023-07-24 17:54:49 -04:00
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn active_time_range_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
not_yet_implemented ( ) ? ;
todo! ( )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn inactive_date_range_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-27 19:59:36 -04:00
let ( remaining , _first_timestamp ) = inactive_timestamp ( context , input ) ? ;
// TODO: Does the space0 at the end of the active/inactive timestamp parsers cause this to be incorrect? I could use a look-behind to make sure the preceding character is not whitespace
let ( remaining , _separator ) = tag ( " -- " ) ( remaining ) ? ;
let ( remaining , _second_timestamp ) = inactive_timestamp ( context , remaining ) ? ;
let ( remaining , _ ) = space0 ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , Timestamp { source } ) )
2023-07-24 17:54:49 -04:00
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn inactive_time_range_timestamp < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , Timestamp < ' s > > {
2023-07-24 17:34:07 -04:00
not_yet_implemented ( ) ? ;
todo! ( )
}
2023-07-27 19:20:28 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
fn date < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
let ( remaining , _year ) = verify ( digit1 , | year : & str | year . len ( ) = = 4 ) ( input ) ? ;
let ( remaining , _ ) = tag ( " - " ) ( remaining ) ? ;
let ( remaining , _month ) = verify ( digit1 , | month : & str | month . len ( ) = = 2 ) ( remaining ) ? ;
let ( remaining , _ ) = tag ( " - " ) ( remaining ) ? ;
let ( remaining , _day_of_month ) =
verify ( digit1 , | day_of_month : & str | day_of_month . len ( ) = = 2 ) ( remaining ) ? ;
let ( remaining , _dayname ) =
opt ( tuple ( ( space1 , parser_with_context! ( dayname ) ( context ) ) ) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn dayname < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
let parser_context =
context . with_additional_node ( ContextElement ::ExitMatcherNode ( ExitMatcherNode {
class : ExitClass ::Beta ,
exit_matcher : & dayname_end ,
} ) ) ;
let ( remaining , body ) = recognize ( verify (
many_till (
anychar ,
parser_with_context! ( exit_matcher_parser ) ( & parser_context ) ,
) ,
| ( body , _end_contents ) | ! body . is_empty ( ) ,
) ) ( input ) ? ;
Ok ( ( remaining , body ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn dayname_end < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
recognize ( verify ( anychar , | c | {
c . is_whitespace ( ) | | " +-]>0123456789 \n " . contains ( * c )
} ) ) ( input )
}
2023-07-27 19:45:57 -04:00
#[ tracing::instrument(ret, level = " debug " ) ]
2023-07-27 19:52:35 -04:00
fn time < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
2023-07-27 19:45:57 -04:00
let ( remaining , _hour ) =
verify ( digit1 , | hour : & str | hour . len ( ) > = 1 & & hour . len ( ) < = 2 ) ( input ) ? ;
let ( remaining , _ ) = tag ( " : " ) ( remaining ) ? ;
let ( remaining , _minute ) = verify ( digit1 , | minute : & str | minute . len ( ) = = 2 ) ( remaining ) ? ;
2023-07-27 19:52:35 -04:00
let ( remaining , _time_rest ) = opt ( parser_with_context! ( time_rest ) ( context ) ) ( remaining ) ? ;
2023-07-27 19:45:57 -04:00
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
2023-07-27 19:52:35 -04:00
fn time_rest < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
2023-07-27 19:45:57 -04:00
let ( remaining , body ) = recognize ( verify (
2023-07-27 19:52:35 -04:00
many_till ( anychar , parser_with_context! ( exit_matcher_parser ) ( context ) ) ,
2023-07-27 19:45:57 -04:00
| ( body , _end_contents ) | ! body . is_empty ( ) ,
) ) ( input ) ? ;
Ok ( ( remaining , body ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn active_time_rest_end < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
alt ( (
recognize ( verify ( anychar , | c | " > \n " . contains ( * c ) ) ) ,
parser_with_context! ( repeater ) ( context ) ,
parser_with_context! ( warning_delay ) ( context ) ,
) ) ( input )
}
#[ tracing::instrument(ret, level = " debug " ) ]
2023-07-27 19:54:33 -04:00
fn inactive_time_rest_end < ' r , ' s > (
context : Context < ' r , ' s > ,
input : & ' s str ,
) -> Res < & ' s str , & ' s str > {
alt ( (
recognize ( verify ( anychar , | c | " ] \n " . contains ( * c ) ) ) ,
parser_with_context! ( repeater ) ( context ) ,
parser_with_context! ( warning_delay ) ( context ) ,
) ) ( input )
}
#[ tracing::instrument(ret, level = " debug " ) ]
2023-07-27 19:45:57 -04:00
fn repeater < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
// + for cumulative type
// ++ for catch-up type
// .+ for restart type
let ( remaining , _mark ) = alt ( ( tag ( " ++ " ) , tag ( " + " ) , tag ( " .+ " ) ) ) ( input ) ? ;
let ( remaining , _value ) = digit1 ( remaining ) ? ;
// h = hour, d = day, w = week, m = month, y = year
let ( remaining , _unit ) = recognize ( one_of ( " hdwmy " ) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}
#[ tracing::instrument(ret, level = " debug " ) ]
fn warning_delay < ' r , ' s > ( context : Context < ' r , ' s > , input : & ' s str ) -> Res < & ' s str , & ' s str > {
// - for all type
// -- for first type
let ( remaining , _mark ) = alt ( ( tag ( " -- " ) , tag ( " - " ) ) ) ( input ) ? ;
let ( remaining , _value ) = digit1 ( remaining ) ? ;
// h = hour, d = day, w = week, m = month, y = year
let ( remaining , _unit ) = recognize ( one_of ( " hdwmy " ) ) ( remaining ) ? ;
let source = get_consumed ( input , remaining ) ;
Ok ( ( remaining , source ) )
}