Skip to content

Commit

Permalink
Overhauled error system to make labels a first-class abstraction and … (
Browse files Browse the repository at this point in the history
#712)

* Overhauled error system to make labels a first-class abstraction and minimise missing labels

* Handle keywords more elegantly

* Fixed tests

* Fixed broken tests

* Appease clippy

* Added MSRV to Cargo.toml

* Fixed MSRV violation
  • Loading branch information
zesterer authored Jan 1, 2025
1 parent ae01819 commit 282bf5e
Show file tree
Hide file tree
Showing 15 changed files with 598 additions and 315 deletions.
9 changes: 3 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exclude = [
"/benches/samples/*",
]
build = "build.rs"
rust-version = "1.65"

[features]
default = ["std", "stacker"]
Expand All @@ -35,9 +36,6 @@ memoization = []
# Allows extending chumsky by writing your own parser implementations.
extension = []

# Enable support for parser labelling
label = []

# Make builtin parsers such as `Boxed` use atomic instead of non-atomic internals.
sync = ["spin"]

Expand Down Expand Up @@ -65,7 +63,7 @@ docsrs = ["dep:vergen-gix"]
# An alias of all features that work with the stable compiler.
# Do not use this feature, its removal is not considered a breaking change and its behaviour may change.
# If you're working on chumsky and you're adding a feature that does not require nightly support, please add it to this list.
_test_stable = ["std", "stacker", "memoization", "extension", "label", "sync"]
_test_stable = ["std", "stacker", "memoization", "extension", "sync"]

[package.metadata.docs.rs]
all-features = true
Expand Down Expand Up @@ -129,7 +127,6 @@ harness = false

[[example]]
name = "nano_rust"
required-features = ["label"]

[[example]]
name = "json"
Expand All @@ -145,4 +142,4 @@ required-features = ["std"]

[[example]]
name = "mini_ml"
required-features = ["pratt", "label"]
required-features = ["pratt"]
3 changes: 1 addition & 2 deletions benches/cbor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

mod utils;

Expand Down
12 changes: 6 additions & 6 deletions examples/io.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use chumsky::extra::ParserExtra;
use chumsky::input::IoInput;
use chumsky::prelude::*;
use std::env;
use std::fs::File;
use chumsky::{error::LabelError, extra::ParserExtra, input::IoInput, prelude::*, util::MaybeRef};
use std::{env, fs::File};

#[allow(unused)]
#[derive(Debug)]
Expand All @@ -29,7 +26,10 @@ fn digits<'a, E: ParserExtra<'a, IoInput<File>>>() -> impl Parser<'a, IoInput<Fi
.map(|v| String::from_utf8_lossy(&v).to_string())
}

fn parser<'a, E: ParserExtra<'a, IoInput<File>>>() -> impl Parser<'a, IoInput<File>, Vec<Foo>, E> {
fn parser<'a, E: ParserExtra<'a, IoInput<File>>>() -> impl Parser<'a, IoInput<File>, Vec<Foo>, E>
where
E::Error: LabelError<'a, IoInput<File>, MaybeRef<'a, u8>>,
{
group((ident(), just(b':').padded(), digits()))
.map(|(name, _, digits)| Foo {
name,
Expand Down
18 changes: 12 additions & 6 deletions src/combinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ where
Ok(M::bind(|| out))
} else {
let err_span = inp.span_since(&before);
inp.add_alt(None, None, err_span);
inp.add_alt([DefaultExpected::SomethingElse], None, err_span);
Err(())
}
})
Expand Down Expand Up @@ -814,7 +814,8 @@ where
inp.add_alt_err(&before.inner /*&err.pos*/, err.err);
} else {
let err_span = inp.span_since(&before);
inp.add_alt(None, None, err_span);
// TODO: Is this an appropriate way to handle infinite recursion?
inp.add_alt([], None, err_span);
}
return Err(());
}
Expand Down Expand Up @@ -1992,7 +1993,7 @@ where
{
#[inline]
fn go<M: Mode>(&self, inp: &mut InputRef<'src, '_, I, E>) -> PResult<M, C> {
let before = inp.cursor();
// let before = inp.cursor();
let mut output = M::bind(|| C::uninit());
let mut iter_state = self.parser.make_iter::<M>(inp)?;
for idx in 0..C::LEN {
Expand All @@ -2001,8 +2002,9 @@ where
M::combine_mut(&mut output, out, |c, out| C::write(c, idx, out));
}
Ok(None) => {
let span = inp.span_since(&before);
inp.add_alt(None, None, span);
// let span = inp.span_since(&before);
// We don't add an alt here because we assume the inner parser will. Is this safe to assume?
// inp.add_alt([ExpectedMoreElements(Some(C::LEN - idx))], None, span);
// SAFETY: We're guaranteed to have initialized up to `idx` values
M::map(output, |mut output| unsafe {
C::drop_before(&mut output, idx)
Expand Down Expand Up @@ -2131,7 +2133,11 @@ where
match result {
Ok(()) => {
let found = inp.next_inner();
inp.add_alt(None, found.map(|f| f.into()), result_span);
inp.add_alt(
[DefaultExpected::SomethingElse],
found.map(|f| f.into()),
result_span,
);
Err(())
}
Err(()) => Ok(M::bind(|| ())),
Expand Down
Loading

0 comments on commit 282bf5e

Please sign in to comment.