Skip to content

Commit

Permalink
Merge pull request #538 from epage/error
Browse files Browse the repository at this point in the history
docs: Round out our error documentation
  • Loading branch information
epage authored Jun 6, 2024
2 parents 8ce95f8 + 6268cf4 commit 7b6a680
Show file tree
Hide file tree
Showing 10 changed files with 810 additions and 184 deletions.
19 changes: 15 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ snapbox = { version = "0.6.0", features = ["examples"] }
circular = "0.3.0"
rustc-hash = "1.1.0"
automod = "1.0.14"
annotate-snippets = "0.11.3"

[profile.bench]
debug = true
Expand Down
43 changes: 36 additions & 7 deletions examples/custom_error.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,57 @@
use winnow::error::AddContext;
use winnow::error::ErrMode;
use winnow::error::ErrorKind;
use winnow::error::FromExternalError;
use winnow::error::ParserError;
use winnow::prelude::*;
use winnow::stream::Stream;

#[derive(Debug, PartialEq, Eq)]
#[derive(Debug)]
pub enum CustomError<I> {
MyError,
Nom(I, ErrorKind),
Winnow(I, ErrorKind),
External {
cause: Box<dyn std::error::Error + Send + Sync + 'static>,
input: I,
kind: ErrorKind,
},
}

impl<I: Stream + Clone> ParserError<I> for CustomError<I> {
fn from_error_kind(input: &I, kind: ErrorKind) -> Self {
CustomError::Nom(input.clone(), kind)
CustomError::Winnow(input.clone(), kind)
}

fn append(self, _: &I, _: &<I as Stream>::Checkpoint, _: ErrorKind) -> Self {
self
}
}

impl<C, I: Stream> AddContext<I, C> for CustomError<I> {
#[inline]
fn add_context(
self,
_input: &I,
_token_start: &<I as Stream>::Checkpoint,
_context: C,
) -> Self {
self
}
}

impl<I: Stream + Clone, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E>
for CustomError<I>
{
#[inline]
fn from_external_error(input: &I, kind: ErrorKind, e: E) -> Self {
CustomError::External {
cause: Box::new(e),
input: input.clone(),
kind,
}
}
}

pub fn parse<'s>(_input: &mut &'s str) -> PResult<&'s str, CustomError<&'s str>> {
Err(ErrMode::Backtrack(CustomError::MyError))
}
Expand All @@ -33,9 +65,6 @@ mod tests {
#[test]
fn it_works() {
let err = parse.parse_next(&mut "").unwrap_err();
match err {
ErrMode::Backtrack(e) => assert_eq!(e, CustomError::MyError),
_ => panic!("Unexpected error: {:?}", err),
}
assert!(matches!(err, ErrMode::Backtrack(CustomError::MyError)));
}
}
31 changes: 24 additions & 7 deletions src/_topic/error.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
//! # Custom Errors
//!
//! Between [`ContextError`], [`Parser::context`], and [`cut_err`],
//! most error needs will likely be met
//! (see [tutorial][chapter_6]).
//! When that isn't the case, you can implement your own error type.
//! A lot can be accomplished with the built-in error tools, like:
//! - [`ContextError`]
//! - [`Parser::context`]
//! - [`cut_err`]
//!
//! The most basic error trait is [`ParserError`].
//! *(see [tutorial][chapter_7])*
//!
//! Most other needs can likely be met by using a custom context type with [`ContextError`] instead
//! of [`StrContext`].
//! This will require implementing a custom renderer.
//!
//! ## `ParserError` Trait
//!
//! When needed, you can also create your own type that implements [`ParserError`].
//!
//! Optional traits include:
//! - [`AddContext`]
//! - [`FromExternalError`]
//! - [`ErrorConvert`]
//!
//! # Example
//! There are multiple strategies for implementing support for [`AddContext`] and [`FromExternalError`]:
//! - Make your error type generic over the context or external error
//! - Require a trait for the context or external error and `Box` it
//! - Make the context an enum like [`StrContext`]
//! - Implement the trait multiple times, one for each concrete context or external error type,
//! allowing custom behavior per type
//!
//! Example:
//!```rust
#![doc = include_str!("../../examples/custom_error.rs")]
//!```
#![allow(unused_imports)]
use crate::combinator::cut_err;
use crate::error::ContextError;
use crate::error::ErrorConvert;
use crate::error::StrContext;
use crate::Parser;
use crate::_tutorial::chapter_6;
use crate::_tutorial::chapter_7;
use crate::error::AddContext;
use crate::error::FromExternalError;
use crate::error::ParserError;
4 changes: 2 additions & 2 deletions src/_tutorial/chapter_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! - On success, the parser will return the processed data. The input will be advanced to the end of
//! what was processed, pointing to what will be parsed next.
//! - If the parser failed, then there are multiple errors that could be returned.
//! We'll explore this further in [`chapter_6`].
//! We'll explore this further in [`chapter_7`].
//!
//! ```text
//! ┌─► Ok(what matched the parser)
Expand All @@ -36,7 +36,7 @@
//! To combine parsers, we need a common way to refer to them which is where the [`Parser<I, O, E>`]
//! trait comes in with [`Parser::parse_next`] being the primary way to drive
//! parsing forward.
//! In [`chapter_7`], we'll cover how to integrate these into your application, particularly with
//! In [`chapter_6`], we'll cover how to integrate these into your application, particularly with
//! [`Parser::parse`].
//!
//! You'll note that `I` and `O` are parameterized -- while most of the examples in this book
Expand Down
4 changes: 2 additions & 2 deletions src/_tutorial/chapter_3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
//!
//! > **Warning:** the above example is for illustrative purposes and relying on `Result::Ok` or
//! > `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering
//! > [error handling][`chapter_6`#errmode]
//! > [error handling][`chapter_7`#error-cuts]
//!
//! [`opt`] is a parser that encapsulates this pattern of "retry on failure":
//! ```rust
Expand Down Expand Up @@ -359,7 +359,7 @@
//! See [`combinator`] for more alternative parsers.
#![allow(unused_imports)]
use super::chapter_6;
use super::chapter_7;
use crate::combinator;
use crate::combinator::alt;
use crate::combinator::dispatch;
Expand Down
Loading

0 comments on commit 7b6a680

Please sign in to comment.