diff --git a/src/parse.rs b/src/parse.rs index f7be3cb..ac7e89e 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -106,15 +106,15 @@ fn perform_entry_parse(entry: &str) -> IResult<&str, CronEntry> { let (remaining, specifiers) = separated_five_tuple( char(' '), // minute - parse_common_specifier, + list_or_single_specifier(parse_common_specifier), // hour - parse_common_specifier, + list_or_single_specifier(parse_common_specifier), // day of month - parse_common_specifier, + list_or_single_specifier(parse_common_specifier), // month - parse_month_specifier, + list_or_single_specifier(parse_month_specifier), // day of week - parse_day_of_week_specifier, + list_or_single_specifier(parse_day_of_week_specifier), )(entry)?; let parsed_entry = CronEntry { @@ -134,76 +134,41 @@ fn perform_entry_parse(entry: &str) -> IResult<&str, CronEntry> { } fn parse_month_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { - // TODO: there's a lot of repetition right here I don't want to clean up this second, - // between this and the other callsites of parse_list_or_element - parse_list_or_element( - parse_month_list_element_specifier, - alt(( - parse_month_list_element_specifier, - simple::parse_star_specifier, - )), - )(chunk) -} - -fn parse_month_list_element_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { alt(( compound::parse_month_range_specifier, word::parse_month, - parse_list_element_common_specifier, + parse_common_specifier, ))(chunk) } fn parse_day_of_week_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { - parse_list_or_element( - parse_day_of_week_list_element_specifier, - alt(( - parse_day_of_week_list_element_specifier, - simple::parse_star_specifier, - )), - )(chunk) -} - -fn parse_day_of_week_list_element_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { alt(( compound::parse_day_of_week_range_specifier, word::parse_day_of_week, - parse_list_element_common_specifier, + parse_common_specifier, ))(chunk) } fn parse_common_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { - parse_list_or_element( - parse_list_element_common_specifier, - parse_standalone_common_specifier, - )(chunk) -} - -fn parse_standalone_common_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { - alt(( - parse_list_element_common_specifier, - simple::parse_star_specifier, - ))(chunk) -} - -fn parse_list_element_common_specifier(chunk: &str) -> IResult<&str, CronSpecifier> { alt(( compound::parse_numeric_range_specifier, simple::parse_numeric_specifier, ))(chunk) } -fn parse_list_or_element<'a, PL, PB, E>( - list_element_parser: PL, - base_parser: PB, +/// Make a parser that will parse either a list of specifiers, or a single one. Each list element must match +/// the given parser. A single specifier must either match this parser, or be * +fn list_or_single_specifier<'a, P, E>( + list_element_parser: P, ) -> impl FnMut(&'a str) -> IResult<&'a str, CronSpecifier, E> where - PL: Parser<&'a str, CronSpecifier, E> + Copy, - PB: Parser<&'a str, CronSpecifier, E>, + P: Parser<&'a str, CronSpecifier, E> + Copy, E: nom::error::ParseError<&'a str>, { alt(( - compound::make_several_specifier_parser(list_element_parser), - base_parser, + compound::several_specifiers(list_element_parser), + list_element_parser, + simple::parse_star_specifier, )) } diff --git a/src/parse/compound.rs b/src/parse/compound.rs index b97e1b5..ed0229c 100644 --- a/src/parse/compound.rs +++ b/src/parse/compound.rs @@ -13,7 +13,7 @@ use std::ops::RangeFrom; /// Make a parser that will parse a list specifier in a cron entry. Each part of the list must be matched by /// `component_parser` -pub(super) fn make_several_specifier_parser
( +pub(super) fn several_specifiers
(
component_parser: P,
) -> impl FnMut(I) -> IResult
where
@@ -42,13 +42,25 @@ where
}
/// Parse a simple numeric range specifier, such as 5-10.
-pub(super) fn parse_numeric_range_specifier(chunk: &str) -> IResult<&str, CronSpecifier> {
+pub(super) fn parse_numeric_range_specifier<'a, E>(
+ chunk: &'a str,
+) -> IResult<&'a str, CronSpecifier, E>
+where
+ E: nom::error::ParseError<&'a str>
+ + nom::error::FromExternalError<&'a str, std::num::ParseIntError>,
+{
build_range_parser(simple::parse_number, simple::parse_number)(chunk)
}
/// Parse a day of week range specifier, with the left/right of the ranges either being the numeric
/// versions of a day of the week, their word forms, or a combination of both.
-pub(super) fn parse_day_of_week_range_specifier(chunk: &str) -> IResult<&str, CronSpecifier> {
+pub(super) fn parse_day_of_week_range_specifier<'a, E>(
+ chunk: &'a str,
+) -> IResult<&'a str, CronSpecifier, E>
+where
+ E: nom::error::ParseError<&'a str>
+ + nom::error::FromExternalError<&'a str, std::num::ParseIntError>,
+{
build_range_parser(
parse_day_of_week_range_branch,
parse_day_of_week_range_branch,
@@ -57,18 +69,32 @@ pub(super) fn parse_day_of_week_range_specifier(chunk: &str) -> IResult<&str, Cr
/// Parse a month range specifier, with the left/right of the ranges either being the numeric
/// versions of a month, their word forms, or a combination of both.
-pub(super) fn parse_month_range_specifier(chunk: &str) -> IResult<&str, CronSpecifier> {
+pub(super) fn parse_month_range_specifier<'a, E>(
+ chunk: &'a str,
+) -> IResult<&'a str, CronSpecifier, E>
+where
+ E: nom::error::ParseError<&'a str>
+ + nom::error::FromExternalError<&'a str, std::num::ParseIntError>,
+{
build_range_parser(parse_month_range_branch, parse_month_range_branch)(chunk)
}
// unfortunately, these branch functions must be broken out into their own functions,
// as in order for `build_range_parser` to work, need `Copy` types, which the impl that
// alt returns is not.
-fn parse_day_of_week_range_branch(chunk: &str) -> IResult<&str, u8> {
+fn parse_day_of_week_range_branch<'a, E>(chunk: &'a str) -> IResult<&'a str, u8, E>
+where
+ E: nom::error::ParseError<&'a str>
+ + nom::error::FromExternalError<&'a str, std::num::ParseIntError>,
+{
alt((word::parse_day_of_week_raw, simple::parse_number))(chunk)
}
-fn parse_month_range_branch(chunk: &str) -> IResult<&str, u8> {
+fn parse_month_range_branch<'a, E>(chunk: &'a str) -> IResult<&'a str, u8, E>
+where
+ E: nom::error::ParseError<&'a str>
+ + nom::error::FromExternalError<&'a str, std::num::ParseIntError>,
+{
alt((word::parse_month_raw, simple::parse_number))(chunk)
}
diff --git a/src/parse/simple.rs b/src/parse/simple.rs
index c012a5b..b37e3d3 100644
--- a/src/parse/simple.rs
+++ b/src/parse/simple.rs
@@ -4,24 +4,31 @@
use nom::{
character::complete::{char, digit1},
combinator::map_res,
+ error::FromExternalError,
IResult,
};
use crate::CronSpecifier;
-use std::str::FromStr;
/// Parse a raw number, which can be later used to form a specifier.
-pub(super) fn parse_number(chunk: &str) -> IResult<&str, u8> {
+pub(super) fn parse_number<'a, E>(chunk: &'a str) -> IResult<&'a str, u8, E>
+where
+ E: nom::error::ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
+{
map_res(digit1, str::parse)(chunk)
}
-pub(super) fn parse_numeric_specifier(chunk: &str) -> IResult<&str, CronSpecifier> {
- map_res::<_, _, _, _,