Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/winnow/src/_tutorial/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 25 kB image not shown  

Quelle  chapter_7.rs

  Sprache: Rust
 

//! # Chapter 7: Error Reporting
//!
//! ## Context
//!
//! With [`Parser::parse`] we get errors that point to the failure but don't explain the reason for
//! the failure:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! #     type Err = String;
//! #
//! #     fn from_str(input: &str) -> Result<Self, Self::Err> {
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//! #             .parse(input)
//! #             .map_err(|e| e.to_string())
//! #     }
//! # }
//! #
//! // ...
//!
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! #     alt((
//! #         ("0b", parse_bin_digits),
//! #         ("0o", parse_oct_digits),
//! #         ("0d", parse_dec_digits),
//! #         ("0x", parse_hex_digits),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "0xZZ";
//!     let error = "\
//! 0xZZ
//!   ^
//! ";
//!     assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! Back in [`chapter_1`], we glossed over the `Err` variant of [`Result`].  `Result<O>` is
//! actually short for `Result<O, E=ContextError>` where [`ContextError`] is a relatively cheap
//! way of building up reasonable errors for humans.
//!
//! You can use [`Parser::context`] to annotate the error with custom types
//! while unwinding to further clarify the error:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! use winnow::error::StrContext;
//! use winnow::error::StrContextValue;
//!
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! #     type Err = String;
//! #
//! #     fn from_str(input: &str) -> Result<Self, Self::Err> {
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//! #             .parse(input)
//! #             .map_err(|e| e.to_string())
//! #     }
//! # }
//! #
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//!     alt((
//!         ("0b", parse_bin_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("binary"))),
//!         ("0o", parse_oct_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("octal"))),
//!         ("0d", parse_dec_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//!         ("0x", parse_hex_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//!     )).parse_next(input)
//! }
//!
//! // ...
//!
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "0xZZ";
//!     let error = "\
//! 0xZZ
//!   ^
//! invalid digit
//! expected hexadecimal";
//!     assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! If you remember back to [`chapter_3`], [`alt`] will only report the last error.
//! So if the parsers fail for any reason, like a bad radix, it will be reported as an invalid
//! hexadecimal value:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! #
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! #     type Err = String;
//! #
//! #     fn from_str(input: &str) -> Result<Self, Self::Err> {
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//! #             .parse(input)
//! #             .map_err(|e| e.to_string())
//! #     }
//! # }
//! #
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! #     alt((
//! #         ("0b", parse_bin_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! #         ("0o", parse_oct_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! #         ("0d", parse_dec_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! #         ("0x", parse_hex_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "100";
//!     let error = "\
//! 100
//! ^
//! invalid digit
//! expected hexadecimal";
//!     assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//! We can improve this with [`fail`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! use winnow::error::StrContext;
//! use winnow::error::StrContextValue;
//!
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! #     type Err = String;
//! #
//! #     fn from_str(input: &str) -> Result<Self, Self::Err> {
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//! #             .parse(input)
//! #             .map_err(|e| e.to_string())
//! #     }
//! # }
//! #
//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//!     alt((
//!         ("0b", parse_bin_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("binary"))),
//!         ("0o", parse_oct_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("octal"))),
//!         ("0d", parse_dec_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//!         ("0x", parse_hex_digits)
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//!         fail
//!           .context(StrContext::Label("radix prefix"))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//!     )).parse_next(input)
//! }
//!
//! // ...
//!
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "100";
//!     let error = "\
//! 100
//! ^
//! invalid radix prefix
//! expected `0b`, `0o`, `0d`, `0x`";
//!     assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! ## Error Cuts
//!
//! We still have the issue that we are falling-through when the radix is valid but the digits
//! don't match it:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::Result;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! #
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! #     type Err = String;
//! #
//! #     fn from_str(input: &str) -> Result<Self, Self::Err> {
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//! #             .parse(input)
//! #             .map_err(|e| e.to_string())
//! #     }
//! # }
//! #
//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
//! #     alt((
//! #         ("0b", parse_bin_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! #         ("0o", parse_oct_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! #         ("0d", parse_dec_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! #         ("0x", parse_hex_digits)
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! #         fail
//! #           .context(StrContext::Label("radix prefix"))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "0b5";
//!     let error = "\
//! 0b5
//! ^
//! invalid radix prefix
//! expected `0b`, `0o`, `0d`, `0x`";
//!     assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! Winnow provides an error wrapper, [`ErrMode<ContextError>`], so different failure modes can affect parsing.
//! [`ErrMode`] is an enum with [`Backtrack`] and [`Cut`] variants (ignore [`Incomplete`] as its only
//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that
//! other parsing branches will be attempted on failure, like the next case of an [`alt`].  [`Cut`]
//! shortcircuits all other branches, immediately reporting the error.
//!
//! To make [`ErrMode`] more convenient, Winnow provides [`ModalResult`]:
//! ```rust
//! # use winnow::error::ContextError;
//! # use winnow::error::ErrMode;
//! pub type ModalResult<O, E = ContextError> = Result<O, ErrMode<E>>;
//! ```
//!
//! So we can get the correct `context` by changing to [`ModalResult`] and adding [`cut_err`]:
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! use winnow::combinator::cut_err;
//!
//! #
//! # #[derive(Debug, PartialEq, Eq)]
//! # pub struct Hex(usize);
//! #
//! # impl std::str::FromStr for Hex {
//! #     type Err = String;
//! #
//! #     fn from_str(input: &str) -> Result<Self, Self::Err> {
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//! #             .parse(input)
//! #             .map_err(|e| e.to_string())
//! #     }
//! # }
//! #
//! fn parse_digits<'s>(input: &mut &'s str) -> ModalResult<(&'s str, &'s str)> {
//!     alt((
//!         ("0b", cut_err(parse_bin_digits))
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("binary"))),
//!         ("0o", cut_err(parse_oct_digits))
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("octal"))),
//!         ("0d", cut_err(parse_dec_digits))
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//!         ("0x", cut_err(parse_hex_digits))
//!           .context(StrContext::Label("digit"))
//!           .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//!         fail
//!           .context(StrContext::Label("radix prefix"))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//!           .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//!     )).parse_next(input)
//! }
//!
//! // ...
//!
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "0b5";
//!     let error = "\
//! 0b5
//!   ^
//! invalid digit
//! expected binary";
//!     assert_eq!(input.parse::<Hex>().unwrap_err(), error);
//! }
//! ```
//!
//! ## Error Adaptation and Rendering
//!
//! While Winnow can provide basic rendering of errors, your application can have various demands
//! beyond the basics provided like
//! - Correctly reporting columns with unicode
//! - Conforming to a specific layout
//!
//! For example, to get rustc-like errors with [`annotate-snippets`](https://crates.io/crates/annotate-snippets):
//! ```rust
//! # use winnow::prelude::*;
//! # use winnow::token::take_while;
//! # use winnow::combinator::alt;
//! # use winnow::token::take;
//! # use winnow::combinator::fail;
//! # use winnow::Parser;
//! # use winnow::error::ParseError;
//! # use winnow::error::ContextError;
//! # use winnow::error::StrContext;
//! # use winnow::error::StrContextValue;
//! # use winnow::combinator::cut_err;
//! #
//! #
//! #[derive(Debug, PartialEq, Eq)]
//! pub struct Hex(usize);
//!
//! impl std::str::FromStr for Hex {
//!     type Err = HexError;
//!
//!     fn from_str(input: &str) -> Result<Self, Self::Err> {
//!         // ...
//! #         parse_digits
//! #             .try_map(|(t, v)| match t {
//! #                "0b" => usize::from_str_radix(v, 2),
//! #                "0o" => usize::from_str_radix(v, 8),
//! #                "0d" => usize::from_str_radix(v, 10),
//! #                "0x" => usize::from_str_radix(v, 16),
//! #                _ => unreachable!("`parse_digits` doesn't return `{t}`"),
//! #              })
//! #             .map(Hex)
//!             .parse(input)
//!             .map_err(|e| HexError::from_parse(e))
//!     }
//! }
//!
//! #[derive(Debug)]
//! pub struct HexError {
//!     message: String,
//!     // Byte spans are tracked, rather than line and column.
//!     // This makes it easier to operate on programmatically
//!     // and doesn't limit us to one definition for column count
//!     // which can depend on the output medium and application.
//!     span: std::ops::Range<usize>,
//!     input: String,
//! }
//!
//! impl HexError {
//!     // Avoiding `From` so `winnow` types don't become part of our public API
//!     fn from_parse(error: ParseError<&str, ContextError>) -> Self {
//!         // The default renderer for `ContextError` is still used but that can be
//!         // customized as well to better fit your needs.
//!         let message = error.inner().to_string();
//!         let input = (*error.input()).to_owned();
//!         // Assume the error span is only for the first `char`.
//!         let span = error.char_span();
//!         Self {
//!             message,
//!             span,
//!             input,
//!         }
//!     }
//! }
//!
//! impl std::fmt::Display for HexError {
//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//!         let message = annotate_snippets::Level::Error.title(&self.message)
//!             .snippet(annotate_snippets::Snippet::source(&self.input)
//!                 .fold(true)
//!                 .annotation(annotate_snippets::Level::Error.span(self.span.clone()))
//!             );
//!         let renderer = annotate_snippets::Renderer::plain();
//!         let rendered = renderer.render(message);
//!         rendered.fmt(f)
//!     }
//! }
//!
//! impl std::error::Error for HexError {}
//!
//! # fn parse_digits<'s>(input: &mut &'s str) -> ModalResult<(&'s str, &'s str)> {
//! #     alt((
//! #         ("0b", cut_err(parse_bin_digits))
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("binary"))),
//! #         ("0o", cut_err(parse_oct_digits))
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("octal"))),
//! #         ("0d", cut_err(parse_dec_digits))
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("decimal"))),
//! #         ("0x", cut_err(parse_hex_digits))
//! #           .context(StrContext::Label("digit"))
//! #           .context(StrContext::Expected(StrContextValue::Description("hexadecimal"))),
//! #         fail
//! #           .context(StrContext::Label("radix prefix"))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0b")))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0o")))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0d")))
//! #           .context(StrContext::Expected(StrContextValue::StringLiteral("0x"))),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='1'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='7'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #     )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> ModalResult<&'s str> {
//! #     take_while(1.., (
//! #         ('0'..='9'),
//! #         ('A'..='F'),
//! #         ('a'..='f'),
//! #     )).parse_next(input)
//! # }
//! fn main() {
//!     let input = "0b5";
//!     let error = "\
//! error: invalid digit
//! expected binary
//!   |
//! 1 | 0b5
//!   |   ^
//!   |";
//!     assert_eq!(input.parse::<Hex>().unwrap_err().to_string(), error);
//! }
//! ```
//!
//! To add spans to your parsed data for inclusion in semantic errors, see [`Parser::with_span`].
//!
//! For richer syntactic with spans,
//! consider separating lexing and parsing and annotating your tokens with [`Parser::with_span`].

#![allow(unused_imports)]
use super::chapter_1;
use super::chapter_3;
use crate::combinator::alt;
use crate::combinator::cut_err;
use crate::combinator::fail;
use crate::error::ContextError;
use crate::error::ErrMode;
use crate::error::ErrMode::*;
use crate::ModalResult;
use crate::Parser;
use crate::Result;
use crate::_topic;

pub use super::chapter_6 as previous;
pub use super::chapter_8 as next;
pub use crate::_tutorial as table_of_contents;

Messung V0.5 in Prozent
C=58 H=92 G=76

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.