Replies: 3 comments
-
I'd expect that |
Beta Was this translation helpful? Give feedback.
0 replies
-
Somehow work around with: #[derive(Debug, Clone, thiserror::Error)]
#[error("{0}")]
struct Context(String);
fn parse_minutes(input: &mut Located<&str>) -> PResult<MinuteExpr> {
fn match_asterisk(input: &mut Located<&str>) -> PResult<MinuteExpr> {
literal("*").parse_next(input).map(|_| MinuteExpr::Asterisk)
}
fn match_single_number(input: &mut Located<&str>) -> PResult<MinuteExpr> {
let verifier = take_while(0.., |_| true).try_map(|minute: &str| {
let minute = minute.parse::<u8>().map_err(|err| Context(format!("failed to parse minute {minute}; {err}")))?;
if (0..=59).contains(&minute) {
Ok(MinuteExpr::PossibleValues(BTreeSet::from_iter(vec![minute])))
} else {
Err(Context(format!("minute must be in the range 0..=59; found: {minute}")))
}
});
digit1.and_then(cut_err(verifier)).parse_next(input)
}
let failure = fail.context(StrContext::Label("crontab minute expression"));
alt((match_asterisk, match_single_number, failure)).parse_next(input)
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
Write an extension: fn parse_single_number_in_range<'a>(
range: RangeInclusive<u8>,
) -> impl Parser<&'a str, u8, ContextError> {
dec_uint.try_map_cut(move |n: u64| {
if n > u8::MAX as u64 {
return Err(StringContext(format!(
"value must be in range {range:?}; found {n}"
)));
}
let n = n as u8;
if range.contains(&n) {
Ok(n)
} else {
Err(StringContext(format!(
"value must be in range {range:?}; found {n}"
)))
}
})
}
trait ParserExt<I, O, E>: Parser<I, O, E> {
#[inline(always)]
fn try_map_cut<G, O2, E2>(self, map: G) -> TryMapCut<Self, G, I, O, O2, E, E2>
where
Self: Sized,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
{
TryMapCut::new(self, map)
}
}
struct TryMapCut<F, G, I, O, O2, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
{
parser: F,
map: G,
i: core::marker::PhantomData<I>,
o: core::marker::PhantomData<O>,
o2: core::marker::PhantomData<O2>,
e: core::marker::PhantomData<E>,
e2: core::marker::PhantomData<E2>,
}
impl<F, G, I, O, O2, E, E2> TryMapCut<F, G, I, O, O2, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
{
#[inline(always)]
fn new(parser: F, map: G) -> Self {
Self {
parser,
map,
i: Default::default(),
o: Default::default(),
o2: Default::default(),
e: Default::default(),
e2: Default::default(),
}
}
}
impl<F, G, I, O, O2, E, E2> Parser<I, O2, E> for TryMapCut<F, G, I, O, O2, E, E2>
where
F: Parser<I, O, E>,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
{
#[inline]
fn parse_next(&mut self, input: &mut I) -> PResult<O2, E> {
let start = input.checkpoint();
let o = self.parser.parse_next(input)?;
let res = (self.map)(o).map_err(|err| {
input.reset(&start);
ErrMode::from_external_error(input, ErrorKind::Verify, err).cut()
});
res
}
}
impl<I, O, E, P> ParserExt<I, O, E> for P where P: Parser<I, O, E> {} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I have a parser like:
I'd like to cut the parsing when matching an uint but it doesn't fall into the range. Currently I have to use a
cut
state value but I wonder if there is some better solution.The current
cut_err
combinator can only apply on the whole parser and cut for either invalid uint OR not a uint, while I'd like to backtrace and retry when not a uint.Beta Was this translation helpful? Give feedback.
All reactions