From f27fe1f543bdc857b16a84a0c530967c8249f79c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jan 2024 09:55:31 -0600 Subject: [PATCH 1/6] docs(ref): Lead users to more cut_err details --- src/combinator/branch.rs | 10 +++++++++- src/combinator/core.rs | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/combinator/branch.rs b/src/combinator/branch.rs index c5eac991..c7597933 100644 --- a/src/combinator/branch.rs +++ b/src/combinator/branch.rs @@ -16,7 +16,10 @@ pub trait Alt { /// Pick the first successful parser /// -/// For tight control over the error, add a final case using [`fail`][crate::combinator::fail]. +/// To stop on an error, rather than trying further cases, see +/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_6]). +/// +/// For tight control over the error when no match is found, add a final case using [`fail`][crate::combinator::fail]. /// Alternatively, with a [custom error type][crate::_topic::error], it is possible to track all /// errors or return the error of the parser that went the farthest in the input data. /// @@ -65,6 +68,11 @@ pub trait Permutation { /// It takes as argument a tuple of parsers, and returns a /// tuple of the parser results. /// +/// To stop on an error, rather than trying further permutations, see +/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_6]). +/// +/// # Example +/// /// ```rust /// # use winnow::{error::ErrMode,error::{InputError, ErrorKind}, error::Needed}; /// # use winnow::prelude::*; diff --git a/src/combinator/core.rs b/src/combinator/core.rs index 2a92d64b..b44b8302 100644 --- a/src/combinator/core.rs +++ b/src/combinator/core.rs @@ -225,6 +225,8 @@ where /// This commits the parse result, preventing alternative branch paths like with /// [`winnow::combinator::alt`][crate::combinator::alt]. /// +/// See the [tutorial][crate::_tutorial::chapter_6] for more details. +/// /// # Example /// /// Without `cut_err`: From 6b64958a77dac297221ae5011760635c1ab32e70 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jan 2024 14:50:23 -0600 Subject: [PATCH 2/6] docs(tutorial): Pull trace docs into tutorial --- src/_tutorial/chapter_7.rs | 1 + src/_tutorial/chapter_8.rs | 34 ++++++++++++++++++++++++++++++++++ src/_tutorial/mod.rs | 1 + src/trace/mod.rs | 9 +-------- 4 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 src/_tutorial/chapter_8.rs diff --git a/src/_tutorial/chapter_7.rs b/src/_tutorial/chapter_7.rs index 7f13f982..659be3a2 100644 --- a/src/_tutorial/chapter_7.rs +++ b/src/_tutorial/chapter_7.rs @@ -115,4 +115,5 @@ use crate::PResult; use crate::Parser; pub use super::chapter_6 as previous; +pub use super::chapter_8 as next; pub use crate::_tutorial as table_of_contents; diff --git a/src/_tutorial/chapter_8.rs b/src/_tutorial/chapter_8.rs new file mode 100644 index 00000000..d36d4ee3 --- /dev/null +++ b/src/_tutorial/chapter_8.rs @@ -0,0 +1,34 @@ +//! # Chapter 8: Debugging +//! +//! When things inevitably go wrong, you can introspect the parsing state by running your test case +//! with `--features debug`: +//! ![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output") +//! +//! You can extend your own parsers to show up by wrapping their body with +//! [`trace`][crate::trace::trace]. Going back to [`do_nothing_parser`][super::chapter_1]. +//! ```rust +//! # use winnow::PResult; +//! # use winnow::Parser; +//! use winnow::trace::trace; +//! +//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> PResult<&'s str> { +//! trace( +//! "do_nothing_parser", +//! |i: &mut _| Ok("") +//! ).parse_next(input) +//! } +//! # +//! # fn main() { +//! # let mut input = "0x1a2b Hello"; +//! # +//! # let output = do_nothing_parser.parse_next(&mut input).unwrap(); +//! # // Same as: +//! # // let output = do_nothing_parser(&mut input).unwrap(); +//! # +//! # assert_eq!(input, "0x1a2b Hello"); +//! # assert_eq!(output, ""); +//! # } +//! ``` + +pub use super::chapter_7 as previous; +pub use crate::_tutorial as table_of_contents; diff --git a/src/_tutorial/mod.rs b/src/_tutorial/mod.rs index 2a4bd61f..3b1680e2 100644 --- a/src/_tutorial/mod.rs +++ b/src/_tutorial/mod.rs @@ -11,3 +11,4 @@ pub mod chapter_4; pub mod chapter_5; pub mod chapter_6; pub mod chapter_7; +pub mod chapter_8; diff --git a/src/trace/mod.rs b/src/trace/mod.rs index 6fe89aca..7eb2f303 100644 --- a/src/trace/mod.rs +++ b/src/trace/mod.rs @@ -1,11 +1,4 @@ //! Parser execution tracing -//! -//! By default, nothing happens and tracing gets compiled away as a no-op. To enable tracing, use -//! `--features debug`. -//! -//! # Example -//! -//!![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output") #![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))] #[cfg(feature = "debug")] @@ -22,7 +15,7 @@ compile_error!("`debug` requires `std`"); /// /// Note that [`Parser::context`] also provides high level trace information. /// -/// See [`trace` module][self] for more details. +/// See [tutorial][crate::_tutorial::chapter_8] for more details. /// /// # Example /// From 93125665285b5322e3a18398538566a100e40ae7 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jan 2024 14:51:56 -0600 Subject: [PATCH 3/6] fix: Consolidate trace parser --- src/_tutorial/chapter_8.rs | 4 ++-- src/{trace => combinator/debug}/internals.rs | 0 src/{trace => combinator/debug}/mod.rs | 1 - src/combinator/mod.rs | 2 ++ src/combinator/parser.rs | 2 +- src/trace.rs | 11 +++++++++++ 6 files changed, 16 insertions(+), 4 deletions(-) rename src/{trace => combinator/debug}/internals.rs (100%) rename src/{trace => combinator/debug}/mod.rs (99%) create mode 100644 src/trace.rs diff --git a/src/_tutorial/chapter_8.rs b/src/_tutorial/chapter_8.rs index d36d4ee3..6ff8f29a 100644 --- a/src/_tutorial/chapter_8.rs +++ b/src/_tutorial/chapter_8.rs @@ -5,11 +5,11 @@ //! ![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output") //! //! You can extend your own parsers to show up by wrapping their body with -//! [`trace`][crate::trace::trace]. Going back to [`do_nothing_parser`][super::chapter_1]. +//! [`trace`][crate::combinator::trace]. Going back to [`do_nothing_parser`][super::chapter_1]. //! ```rust //! # use winnow::PResult; //! # use winnow::Parser; -//! use winnow::trace::trace; +//! use winnow::combinator::trace; //! //! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> PResult<&'s str> { //! trace( diff --git a/src/trace/internals.rs b/src/combinator/debug/internals.rs similarity index 100% rename from src/trace/internals.rs rename to src/combinator/debug/internals.rs diff --git a/src/trace/mod.rs b/src/combinator/debug/mod.rs similarity index 99% rename from src/trace/mod.rs rename to src/combinator/debug/mod.rs index 7eb2f303..4c5b810a 100644 --- a/src/trace/mod.rs +++ b/src/combinator/debug/mod.rs @@ -1,4 +1,3 @@ -//! Parser execution tracing #![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))] #[cfg(feature = "debug")] diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs index a0acf87b..6c529474 100644 --- a/src/combinator/mod.rs +++ b/src/combinator/mod.rs @@ -157,6 +157,7 @@ mod branch; mod core; +mod debug; mod multi; mod parser; mod sequence; @@ -166,6 +167,7 @@ mod tests; pub use self::branch::*; pub use self::core::*; +pub use self::debug::*; pub use self::multi::*; pub use self::parser::*; pub use self::sequence::*; diff --git a/src/combinator/parser.rs b/src/combinator/parser.rs index 80ed11bf..4e984241 100644 --- a/src/combinator/parser.rs +++ b/src/combinator/parser.rs @@ -1,10 +1,10 @@ +use crate::combinator::trace_result; use crate::error::{AddContext, ErrMode, ErrorKind, FromExternalError, ParserError}; use crate::lib::std::borrow::Borrow; use crate::lib::std::ops::Range; use crate::stream::StreamIsPartial; use crate::stream::{Location, Stream}; use crate::trace::trace; -use crate::trace::trace_result; use crate::*; /// Implementation of [`Parser::by_ref`] diff --git a/src/trace.rs b/src/trace.rs new file mode 100644 index 00000000..9c055765 --- /dev/null +++ b/src/trace.rs @@ -0,0 +1,11 @@ +//! Deprecated, replaced with [`winnow::combinator`][crate::combinator] + +/// Deprecated, replaced with [`winnow::combinator::trace`][crate::combinator::trace] +#[deprecated(since = "0.5.35", note = "Replaced with `winnow::combinator::trace`")] +#[inline(always)] +pub fn trace( + name: impl crate::lib::std::fmt::Display, + parser: impl crate::Parser, +) -> impl crate::Parser { + crate::combinator::trace(name, parser) +} From d9d14a0a1472a00b1f3c9945c991d5f2f4f25eb0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jan 2024 14:53:49 -0600 Subject: [PATCH 4/6] refactor: Move off of deprecated 'trace' path --- src/ascii/mod.rs | 2 +- src/binary/bits/mod.rs | 2 +- src/binary/mod.rs | 2 +- src/combinator/branch.rs | 2 +- src/combinator/core.rs | 2 +- src/combinator/debug/mod.rs | 2 +- src/combinator/mod.rs | 2 +- src/combinator/multi.rs | 2 +- src/combinator/parser.rs | 2 +- src/combinator/sequence.rs | 2 +- src/macros/dispatch.rs | 2 +- src/macros/seq.rs | 6 +++--- src/token/mod.rs | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ascii/mod.rs b/src/ascii/mod.rs index 0aacf271..31c532ca 100644 --- a/src/ascii/mod.rs +++ b/src/ascii/mod.rs @@ -10,6 +10,7 @@ use crate::lib::std::ops::{Add, Shl}; use crate::combinator::alt; use crate::combinator::cut_err; use crate::combinator::opt; +use crate::combinator::trace; use crate::error::ParserError; use crate::error::{ErrMode, ErrorKind, Needed}; use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial}; @@ -17,7 +18,6 @@ use crate::stream::{Compare, CompareResult}; use crate::token::one_of; use crate::token::take_till; use crate::token::take_while; -use crate::trace::trace; use crate::PResult; use crate::Parser; diff --git a/src/binary/bits/mod.rs b/src/binary/bits/mod.rs index 16a0f646..4a198c49 100644 --- a/src/binary/bits/mod.rs +++ b/src/binary/bits/mod.rs @@ -4,10 +4,10 @@ #[cfg(test)] mod tests; +use crate::combinator::trace; use crate::error::{ErrMode, ErrorConvert, ErrorKind, Needed, ParserError}; use crate::lib::std::ops::{AddAssign, Div, Shl, Shr}; use crate::stream::{AsBytes, Stream, StreamIsPartial, ToUsize}; -use crate::trace::trace; use crate::{unpeek, IResult, PResult, Parser}; /// Number of bits in a byte diff --git a/src/binary/mod.rs b/src/binary/mod.rs index a80ae6ce..01053a52 100644 --- a/src/binary/mod.rs +++ b/src/binary/mod.rs @@ -8,6 +8,7 @@ pub mod bits; mod tests; use crate::combinator::repeat; +use crate::combinator::trace; use crate::error::ErrMode; use crate::error::ErrorKind; use crate::error::Needed; @@ -17,7 +18,6 @@ use crate::stream::Accumulate; use crate::stream::{AsBytes, Stream, StreamIsPartial}; use crate::stream::{ToUsize, UpdateSlice}; use crate::token::take; -use crate::trace::trace; use crate::PResult; use crate::Parser; diff --git a/src/combinator/branch.rs b/src/combinator/branch.rs index c7597933..7fdcf8dc 100644 --- a/src/combinator/branch.rs +++ b/src/combinator/branch.rs @@ -1,6 +1,6 @@ +use crate::combinator::trace; use crate::error::{ErrMode, ErrorKind, ParserError}; use crate::stream::Stream; -use crate::trace::trace; use crate::*; #[doc(inline)] diff --git a/src/combinator/core.rs b/src/combinator/core.rs index b44b8302..4f764261 100644 --- a/src/combinator/core.rs +++ b/src/combinator/core.rs @@ -1,6 +1,6 @@ +use crate::combinator::trace; use crate::error::{ErrMode, ErrorKind, Needed, ParserError}; use crate::stream::Stream; -use crate::trace::trace; use crate::*; /// Return the remaining input. diff --git a/src/combinator/debug/mod.rs b/src/combinator/debug/mod.rs index 4c5b810a..ee4c2931 100644 --- a/src/combinator/debug/mod.rs +++ b/src/combinator/debug/mod.rs @@ -23,7 +23,7 @@ compile_error!("`debug` requires `std`"); /// # use winnow::token::take_while; /// # use winnow::stream::AsChar; /// # use winnow::prelude::*; -/// use winnow::trace::trace; +/// use winnow::combinator::trace; /// /// fn short_alpha<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> { /// trace("short_alpha", diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs index 6c529474..8ca4348a 100644 --- a/src/combinator/mod.rs +++ b/src/combinator/mod.rs @@ -76,7 +76,7 @@ //! - [`backtrack_err`]: Attempts a parse, allowing alternative parsers to be attempted despite //! use of `cut_err` //! - [`Parser::context`]: Add context to the error if the parser fails -//! - [`trace`][crate::trace::trace]: Print the parse state with the `debug` feature flag +//! - [`trace`]: Print the parse state with the `debug` feature flag //! - [`todo()`]: Placeholder parser //! //! ## Remaining combinators diff --git a/src/combinator/multi.rs b/src/combinator/multi.rs index 0c686942..926d41ee 100644 --- a/src/combinator/multi.rs +++ b/src/combinator/multi.rs @@ -1,12 +1,12 @@ //! Combinators applying their child parser multiple times +use crate::combinator::trace; use crate::error::ErrMode; use crate::error::ErrorKind; use crate::error::ParserError; use crate::stream::Accumulate; use crate::stream::Range; use crate::stream::Stream; -use crate::trace::trace; use crate::PResult; use crate::Parser; diff --git a/src/combinator/parser.rs b/src/combinator/parser.rs index 4e984241..1fb54464 100644 --- a/src/combinator/parser.rs +++ b/src/combinator/parser.rs @@ -1,10 +1,10 @@ +use crate::combinator::trace; use crate::combinator::trace_result; use crate::error::{AddContext, ErrMode, ErrorKind, FromExternalError, ParserError}; use crate::lib::std::borrow::Borrow; use crate::lib::std::ops::Range; use crate::stream::StreamIsPartial; use crate::stream::{Location, Stream}; -use crate::trace::trace; use crate::*; /// Implementation of [`Parser::by_ref`] diff --git a/src/combinator/sequence.rs b/src/combinator/sequence.rs index 4eaa6d14..0f2e6333 100644 --- a/src/combinator/sequence.rs +++ b/src/combinator/sequence.rs @@ -1,6 +1,6 @@ +use crate::combinator::trace; use crate::error::ParserError; use crate::stream::Stream; -use crate::trace::trace; use crate::*; #[doc(inline)] diff --git a/src/macros/dispatch.rs b/src/macros/dispatch.rs index f16cbc31..9305fd70 100644 --- a/src/macros/dispatch.rs +++ b/src/macros/dispatch.rs @@ -41,7 +41,7 @@ #[doc(hidden)] // forced to be visible in intended location macro_rules! dispatch { ($match_parser: expr; $( $pat:pat $(if $pred:expr)? => $expr: expr ),+ $(,)? ) => { - $crate::trace::trace("dispatch", move |i: &mut _| + $crate::combinator::trace("dispatch", move |i: &mut _| { use $crate::Parser; let initial = $match_parser.parse_next(i)?; diff --git a/src/macros/seq.rs b/src/macros/seq.rs index 756f3006..bb1cd25f 100644 --- a/src/macros/seq.rs +++ b/src/macros/seq.rs @@ -64,7 +64,7 @@ #[doc(alias = "struct_parser")] macro_rules! seq { ($name: ident { $($fields: tt)* }) => { - $crate::trace::trace(stringify!($name), move |input: &mut _| { + $crate::combinator::trace(stringify!($name), move |input: &mut _| { use $crate::Parser; $crate::seq_parse_struct_fields!(input; $($fields)*); #[allow(clippy::redundant_field_names)] @@ -72,7 +72,7 @@ macro_rules! seq { }) }; ($name: ident ( $($elements: tt)* )) => { - $crate::trace::trace(stringify!($name), move |input: &mut _| { + $crate::combinator::trace(stringify!($name), move |input: &mut _| { use $crate::Parser; $crate::seq_parse_tuple_fields!( ($($elements)*) ; ).map(|t| { $crate::seq_init_tuple_fields!( @@ -84,7 +84,7 @@ macro_rules! seq { }) }; (( $($elements: tt)* )) => { - $crate::trace::trace("tuple", move |input: &mut _| { + $crate::combinator::trace("tuple", move |input: &mut _| { use $crate::Parser; $crate::seq_parse_tuple_fields!( ($($elements)*) ; ).map(|t| { $crate::seq_init_tuple_fields!( diff --git a/src/token/mod.rs b/src/token/mod.rs index 5855bf73..c5ce432d 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -3,6 +3,7 @@ #[cfg(test)] mod tests; +use crate::combinator::trace; use crate::error::ErrMode; use crate::error::ErrorKind; use crate::error::Needed; @@ -11,7 +12,6 @@ use crate::lib::std::result::Result::Ok; use crate::stream::Range; use crate::stream::{Compare, CompareResult, ContainsToken, FindSlice, SliceLen, Stream}; use crate::stream::{StreamIsPartial, ToUsize}; -use crate::trace::trace; use crate::PResult; use crate::Parser; From 71e52668ced3ff640dbb29e84f065bcac5eb6bac Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jan 2024 15:05:20 -0600 Subject: [PATCH 5/6] docs(topic): Raise visibility of error tutorial --- src/_topic/error.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/_topic/error.rs b/src/_topic/error.rs index c5374b4a..8a401b47 100644 --- a/src/_topic/error.rs +++ b/src/_topic/error.rs @@ -1,13 +1,27 @@ //! # Custom Errors //! -//! The most basic error type is [`ParserError`][crate::error::ParserError] +//! 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. +//! +//! The most basic error trait is [`ParserError`]. //! //! Optional traits include: -//! - [`AddContext`][crate::error::AddContext] -//! - [`FromExternalError`][crate::error::FromExternalError] +//! - [`AddContext`] +//! - [`FromExternalError`] //! //! # Example //! //!```rust #![doc = include_str!("../../examples/custom_error.rs")] //!``` + +#![allow(unused_imports)] +use crate::combinator::cut_err; +use crate::error::ContextError; +use crate::Parser; +use crate::_tutorial::chapter_6; +use crate::error::AddContext; +use crate::error::FromExternalError; +use crate::error::ParserError; From 224688946e61c58f29b9315a720cc681de2fb722 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jan 2024 15:05:24 -0600 Subject: [PATCH 6/6] docs(topic): Raise visibility of debug tutorial --- src/_topic/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_topic/mod.rs b/src/_topic/mod.rs index 79895cec..c7bcc538 100644 --- a/src/_topic/mod.rs +++ b/src/_topic/mod.rs @@ -17,6 +17,7 @@ //! - [Parsing Partial Input][partial] //! - [Custom stream or token][stream] //! - [Custom errors][error] +//! - [Debugging][crate::_tutorial::chapter_8] //! //! See also parsers written with `winnow`: //!