Skip to content
This repository was archived by the owner on Apr 2, 2026. It is now read-only.

Commit 7fbd561

Browse files
authored
fix: update the filter based on the experience of bugs related to try_map (#833)
The old `alt` is used. Errors are given their corresponding location.
1 parent 79b2ab3 commit 7fbd561

3 files changed

Lines changed: 60 additions & 7 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# IDE projects
22
.idea/
3+
.vscode/
34

45
# Project output
56
/target

src/combinator.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,40 @@ where
253253
#[inline(always)]
254254
fn go<M: Mode>(&self, inp: &mut InputRef<'src, '_, I, E>) -> PResult<M, O> {
255255
let before = inp.cursor();
256-
self.parser.go::<Emit>(inp).and_then(|out| {
257-
if (self.filter)(&out) {
258-
Ok(M::bind(|| out))
259-
} else {
260-
let err_span = inp.span_since(&before);
261-
inp.add_alt([DefaultExpected::SomethingElse], None, err_span);
256+
// Remove the pre-inner alt, to be reinserted later so we always preserve it
257+
let old_alt = inp.errors.alt.take();
258+
259+
let res = self.parser.go::<Emit>(inp);
260+
let span = inp.span_since(&before);
261+
let new_alt = inp.errors.alt.take();
262+
263+
match res {
264+
Ok(out) => {
265+
if (self.filter)(&out) {
266+
// If successful, reinsert the original alt and then apply the new alt on top of it, since both are valid
267+
inp.errors.alt = old_alt;
268+
if let Some(new_alt) = new_alt {
269+
inp.add_alt_err(&new_alt.pos, new_alt.err);
270+
}
271+
Ok(M::bind(|| out))
272+
} else {
273+
// If unsuccessful, reinsert the original alt but replace the new alt with the "something else" error (since it overrides it)
274+
let expected = [DefaultExpected::SomethingElse];
275+
let err = E::Error::expected_found(expected, None, span);
276+
inp.errors.alt = old_alt;
277+
inp.add_alt_err(&before.inner, err);
278+
Err(())
279+
}
280+
}
281+
282+
Err(_) => {
283+
inp.errors.alt = old_alt;
284+
if let Some(new_alt) = new_alt {
285+
inp.add_alt_err(&new_alt.pos, new_alt.err);
286+
}
262287
Err(())
263288
}
264-
})
289+
}
265290
}
266291

267292
go_extra!(O);

src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3812,6 +3812,33 @@ mod tests {
38123812
);
38133813
}
38143814

3815+
#[test]
3816+
fn filter() {
3817+
use crate::{DefaultExpected, LabelError};
3818+
3819+
let parser = group((
3820+
just("a").or_not(),
3821+
just("b").filter(|_| false).or_not(),
3822+
just::<_, &str, extra::Err<Rich<_>>>("c"),
3823+
));
3824+
3825+
assert_eq!(
3826+
parser.parse("b").into_output_errors(),
3827+
(
3828+
None,
3829+
vec![LabelError::<&str, _>::expected_found(
3830+
vec![
3831+
DefaultExpected::Token('a'.into()),
3832+
DefaultExpected::SomethingElse,
3833+
DefaultExpected::Token('c'.into()),
3834+
],
3835+
Some('b'.into()),
3836+
SimpleSpan::new((), 0..1)
3837+
)]
3838+
)
3839+
);
3840+
}
3841+
38153842
#[test]
38163843
fn zero_size_custom_failure() {
38173844
fn my_custom<'src>() -> impl Parser<'src, &'src str, ()> {

0 commit comments

Comments
 (0)