Change ErrMode::Cut to ErrMode::Backtrack to allow alt parser flow

This commit is contained in:
Nicholas Still
2025-10-02 13:59:29 -07:00
committed by Daniel Hofstetter
parent 29e368662c
commit 3074fe3baa
2 changed files with 48 additions and 11 deletions
+14 -11
View File
@@ -138,9 +138,10 @@ pub(super) fn iso1(input: &mut &str) -> ModalResult<Date> {
let (year, _, month, _, day) =
(year_str, s('-'), s(dec_uint), s('-'), s(dec_uint)).parse_next(input)?;
// Map err to Backtrack instead of Cut to avoid early termination of parsing
(year, month, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e)))
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
}
/// Parse `[year][month][day]`
@@ -156,7 +157,7 @@ pub(super) fn iso2(input: &mut &str) -> ModalResult<Date> {
(year, month, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e)))
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
}
/// Parse `[year]/[month]/[day]` or `[month]/[day]/[year]` or `[month]/[day]`.
@@ -178,19 +179,21 @@ fn us(input: &mut &str) -> ModalResult<Date> {
let day = day_from_str(s2)?;
(s1, n, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e)))
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
}
Some(s2) => {
// [month]/[day]/[year]
let month = month_from_str(s1)?;
(s2, month, n)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e)))
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
}
None => {
// [month]/[day]
let month = month_from_str(s1)?;
(month, n).try_into().map_err(|e| ErrMode::Cut(ctx_err(e)))
(month, n)
.try_into()
.map_err(|e| ErrMode::Backtrack(ctx_err(e)))
}
}
}
@@ -213,10 +216,10 @@ fn literal1(input: &mut &str) -> ModalResult<Date> {
match year {
Some(year) => (year, month, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e))),
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
None => (month, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e))),
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
}
}
@@ -242,10 +245,10 @@ fn literal2(input: &mut &str) -> ModalResult<Date> {
match year {
Some(year) => (year, month, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e))),
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
None => (month, day)
.try_into()
.map_err(|e| ErrMode::Cut(ctx_err(e))),
.map_err(|e| ErrMode::Backtrack(ctx_err(e))),
}
}
@@ -274,12 +277,12 @@ fn literal_month(input: &mut &str) -> ModalResult<u8> {
fn month_from_str(s: &str) -> ModalResult<u8> {
s.parse::<u8>()
.map_err(|_| ErrMode::Cut(ctx_err("month must be a valid u8 number")))
.map_err(|_| ErrMode::Backtrack(ctx_err("month must be a valid u8 number")))
}
fn day_from_str(s: &str) -> ModalResult<u8> {
s.parse::<u8>()
.map_err(|_| ErrMode::Cut(ctx_err("day must be a valid u8 number")))
.map_err(|_| ErrMode::Backtrack(ctx_err("day must be a valid u8 number")))
}
#[cfg(test)]
+34
View File
@@ -128,3 +128,37 @@ fn test_time_invalid(#[case] input: &str) {
"Input string '{input}' did not produce an error when parsing"
);
}
#[rstest]
#[case::decimal_1_whole("1.123456789 seconds ago")]
#[case::decimal_2_whole("12.123456789 seconds ago")]
#[case::decimal_3_whole("123.123456789 seconds ago")]
#[case::decimal_4_whole("1234.123456789 seconds ago")]
#[case::decimal_5_whole("12345.123456789 seconds ago")]
#[case::decimal_6_whole("123456.123456789 seconds ago")]
#[case::decimal_7_whole("1234567.123456789 seconds ago")]
#[case::decimal_8_whole("12345678.123456789 seconds ago")]
#[case::decimal_9_whole("123456789.123456789 seconds ago")]
#[case::decimal_10_whole("1234567891.123456789 seconds ago")]
#[case::decimal_11_whole("12345678912.123456789 seconds ago")]
#[case::decimal_12_whole("123456789123.123456789 seconds ago")]
fn test_time_seconds_ago(#[case] input: &str) {
let result = parse_datetime::parse_datetime(input);
assert!(
result.is_ok(),
"Input string '{input}', produced {result:?}, instead of Ok(Zoned)"
);
}
#[rstest]
#[case::decimal_13_whole("1234567891234.123456789 seconds ago")]
#[case::decimal_14_whole("12345678912345.123456789 seconds ago")]
#[case::decimal_15_whole("123456789123456.123456789 seconds ago")]
fn test_time_seconds_ago_invalid(#[case] input: &str) {
let result = parse_datetime::parse_datetime(input);
assert_eq!(
result,
Err(parse_datetime::ParseDateTimeError::InvalidInput),
"Input string '{input}' did not produce an error when parsing"
);
}