Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
39
third-party/vendor/winnow/src/_tutorial/chapter_0.rs
vendored
Normal file
39
third-party/vendor/winnow/src/_tutorial/chapter_0.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
//! # Chapter 0: Introduction
|
||||
//!
|
||||
//! This tutorial assumes that you are:
|
||||
//! - Already familiar with Rust
|
||||
//! - Using `winnow` for the first time
|
||||
//!
|
||||
//! The focus will be on parsing in-memory strings (`&str`). Once done, you might want to check the
|
||||
//! [Special Topics][_topic] for more specialized topics or examples.
|
||||
//!
|
||||
//! ## About
|
||||
//!
|
||||
//! `winnow` is a parser-combinator library. In other words, it gives you tools to define:
|
||||
//! - "parsers", or functions that take an input and give back an output
|
||||
//! - "combinators", or functions that take parsers and _combine_ them together!
|
||||
//!
|
||||
//! While "combinator" might be an unfamiliar word, you are likely using them in your rust code
|
||||
//! today, like with the [`Iterator`] trait:
|
||||
//! ```rust
|
||||
//! let data = vec![1, 2, 3, 4, 5];
|
||||
//! let even_count = data.iter()
|
||||
//! .copied() // combinator
|
||||
//! .filter(|d| d % 2 == 0) // combinator
|
||||
//! .count(); // combinator
|
||||
//! ```
|
||||
//!
|
||||
//! Parser combinators are great because:
|
||||
//!
|
||||
//! - The parsers are small and easy to write
|
||||
//! - The parsers components are easy to reuse (if they're general enough, please add them to winnow!)
|
||||
//! - The parsers components are easy to test separately (unit tests and property-based tests)
|
||||
//! - The parser combination code looks close to the grammar you would have written
|
||||
//! - You can build partial parsers, specific to the data you need at the moment, and ignore the rest
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use crate::_topic;
|
||||
use std::iter::Iterator;
|
||||
|
||||
pub use super::chapter_1 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
86
third-party/vendor/winnow/src/_tutorial/chapter_1.rs
vendored
Normal file
86
third-party/vendor/winnow/src/_tutorial/chapter_1.rs
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//! # Chapter 1: The Winnow Way
|
||||
//!
|
||||
//! First of all, we need to understand the way that winnow thinks about parsing.
|
||||
//! As discussed in the introduction, winnow lets us build simple parsers, and
|
||||
//! then combine them (using "combinators").
|
||||
//!
|
||||
//! Let's discuss what a "parser" actually does. A parser takes an input and returns
|
||||
//! a result, where:
|
||||
//! - `Ok` indicates the parser successfully found what it was looking for; or
|
||||
//! - `Err` indicates the parser could not find what it was looking for.
|
||||
//!
|
||||
//! Parsers do more than just return a binary "success"/"failure" code.
|
||||
//! On success, the parser will return the processed data. The input will be left pointing to
|
||||
//! data that still needs processing
|
||||
//!
|
||||
//! If the parser failed, then there are multiple errors that could be returned.
|
||||
//! For simplicity, however, in the next chapters we will leave these unexplored.
|
||||
//!
|
||||
//! ```text
|
||||
//! ┌─► Ok(what matched the parser)
|
||||
//! ┌─────────┐ │
|
||||
//! my input───►│my parser├──►either──┤
|
||||
//! └─────────┘ └─► Err(...)
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! To represent this model of the world, winnow uses the [`PResult<O>`] type.
|
||||
//! The `Ok` variant has `output: O`;
|
||||
//! whereas the `Err` variant stores an error.
|
||||
//!
|
||||
//! You can import that from:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::PResult;
|
||||
//! ```
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! You'll note that `I` and `O` are parameterized -- while most of the examples in this book
|
||||
//! will be with `&str` (i.e. parsing a string); they do not have to be strings; nor do they
|
||||
//! have to be the same type (consider the simple example where `I = &str`, and `O = u64` -- this
|
||||
//! parses a string into an unsigned integer.)
|
||||
//!
|
||||
//!
|
||||
//! # Let's write our first parser!
|
||||
//!
|
||||
//! The simplest parser we can write is one which successfully does nothing.
|
||||
//!
|
||||
//! To make it easier to implement a [`Parser`], the trait is implemented for
|
||||
//! functions of the form `Fn(&mut I) -> PResult<O>`.
|
||||
//!
|
||||
//! This parser function should take in a `&str`:
|
||||
//!
|
||||
//! - Since it is supposed to succeed, we know it will return the `Ok` variant.
|
||||
//! - Since it does nothing to our input, the remaining input is the same as the input.
|
||||
//! - Since it doesn't parse anything, it also should just return an empty string.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//!
|
||||
//! pub fn do_nothing_parser<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! Ok("")
|
||||
//! }
|
||||
//!
|
||||
//! 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, "");
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use crate::PResult;
|
||||
use crate::Parser;
|
||||
|
||||
pub use super::chapter_0 as previous;
|
||||
pub use super::chapter_2 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
248
third-party/vendor/winnow/src/_tutorial/chapter_2.rs
vendored
Normal file
248
third-party/vendor/winnow/src/_tutorial/chapter_2.rs
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
//! # Chapter 2: Tokens and Tags
|
||||
//!
|
||||
//! The simplest *useful* parser you can write is one which matches tokens.
|
||||
//!
|
||||
//! ## Tokens
|
||||
//!
|
||||
//! [`Stream`] provides some core operations to help with parsing. For example, to process a
|
||||
//! single token, you can do:
|
||||
//! ```rust
|
||||
//! # use winnow::Parser;
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::stream::Stream;
|
||||
//! use winnow::error::ParserError;
|
||||
//! use winnow::error::ErrorKind;
|
||||
//! use winnow::error::ErrMode;
|
||||
//!
|
||||
//! fn parse_prefix(input: &mut &str) -> PResult<char> {
|
||||
//! let c = input.next_token().ok_or_else(|| {
|
||||
//! ErrMode::from_error_kind(input, ErrorKind::Token)
|
||||
//! })?;
|
||||
//! if c != '0' {
|
||||
//! return Err(ErrMode::from_error_kind(input, ErrorKind::Verify));
|
||||
//! }
|
||||
//! Ok(c)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let output = parse_prefix.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, "x1a2b Hello");
|
||||
//! assert_eq!(output, '0');
|
||||
//!
|
||||
//! assert!(parse_prefix.parse_next(&mut "d").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`any`] and [`Parser::verify`] are [`Parser`] building blocks on top of [`Stream`]:
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//! use winnow::token::any;
|
||||
//!
|
||||
//! fn parse_prefix(input: &mut &str) -> PResult<char> {
|
||||
//! any.verify(|c| *c == '0').parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # let mut input = "0x1a2b Hello";
|
||||
//! #
|
||||
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
|
||||
//! #
|
||||
//! # assert_eq!(input, "x1a2b Hello");
|
||||
//! # assert_eq!(output, '0');
|
||||
//! #
|
||||
//! # assert!(parse_prefix.parse_next(&mut "d").is_err());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! Matching a single token literal is common enough that [`Parser`] is implemented for
|
||||
//! `char`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//!
|
||||
//! fn parse_prefix(input: &mut &str) -> PResult<char> {
|
||||
//! '0'.parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # let mut input = "0x1a2b Hello";
|
||||
//! #
|
||||
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
|
||||
//! #
|
||||
//! # assert_eq!(input, "x1a2b Hello");
|
||||
//! # assert_eq!(output, '0');
|
||||
//! #
|
||||
//! # assert!(parse_prefix.parse_next(&mut "d").is_err());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Tags
|
||||
//!
|
||||
//! [`Stream`] also supports processing slices of tokens:
|
||||
//! ```rust
|
||||
//! # use winnow::Parser;
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::stream::Stream;
|
||||
//! use winnow::error::ParserError;
|
||||
//! use winnow::error::ErrorKind;
|
||||
//! use winnow::error::ErrMode;
|
||||
//!
|
||||
//! fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! let expected = "0x";
|
||||
//! if input.len() < expected.len() {
|
||||
//! return Err(ErrMode::from_error_kind(input, ErrorKind::Slice));
|
||||
//! }
|
||||
//! let actual = input.next_slice(expected.len());
|
||||
//! if actual != expected {
|
||||
//! return Err(ErrMode::from_error_kind(input, ErrorKind::Verify));
|
||||
//! }
|
||||
//! Ok(actual)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let output = parse_prefix.parse_next(&mut input).unwrap();
|
||||
//! assert_eq!(input, "1a2b Hello");
|
||||
//! assert_eq!(output, "0x");
|
||||
//!
|
||||
//! assert!(parse_prefix.parse_next(&mut "0o123").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Again, matching a literal is common enough that [`Parser`] is implemented for `&str`:
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::Parser;
|
||||
//!
|
||||
//! fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! "0x".parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # let mut input = "0x1a2b Hello";
|
||||
//! #
|
||||
//! # let output = parse_prefix.parse_next(&mut input).unwrap();
|
||||
//! # assert_eq!(input, "1a2b Hello");
|
||||
//! # assert_eq!(output, "0x");
|
||||
//! #
|
||||
//! # assert!(parse_prefix.parse_next(&mut "0o123").is_err());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! In `winnow`, we call this type of parser a [`tag`]. See [`token`] for additional individual
|
||||
//! and token-slice parsers.
|
||||
//!
|
||||
//! ## Character Classes
|
||||
//!
|
||||
//! Selecting a single `char` or a [`tag`] is fairly limited. Sometimes, you will want to select one of several
|
||||
//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parser:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::Parser;
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::token::one_of;
|
||||
//!
|
||||
//! fn parse_digits(input: &mut &str) -> PResult<char> {
|
||||
//! one_of(('0'..='9', 'a'..='f', 'A'..='F')).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "1a2b Hello";
|
||||
//!
|
||||
//! let output = parse_digits.parse_next(&mut input).unwrap();
|
||||
//! assert_eq!(input, "a2b Hello");
|
||||
//! assert_eq!(output, '1');
|
||||
//!
|
||||
//! assert!(parse_digits.parse_next(&mut "Z").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! > **Aside:** [`one_of`] might look straightforward, a function returning a value that implements `Parser`.
|
||||
//! > Let's look at it more closely as its used above (resolving all generic parameters):
|
||||
//! > ```rust
|
||||
//! > # use winnow::prelude::*;
|
||||
//! > # use winnow::error::InputError;
|
||||
//! > pub fn one_of<'i>(
|
||||
//! > list: &'static [char]
|
||||
//! > ) -> impl Parser<&'i str, char, InputError<&'i str>> {
|
||||
//! > // ...
|
||||
//! > # winnow::token::one_of(list)
|
||||
//! > }
|
||||
//! > ```
|
||||
//! > If you have not programmed in a language where functions are values, the type signature of the
|
||||
//! > [`one_of`] function might be a surprise.
|
||||
//! > The function [`one_of`] *returns a function*. The function it returns is a
|
||||
//! > `Parser`, taking a `&str` and returning an `PResult`. This is a common pattern in winnow for
|
||||
//! > configurable or stateful parsers.
|
||||
//!
|
||||
//! Some of character classes are common enough that a named parser is provided, like with:
|
||||
//! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`)
|
||||
//! - [`newline`][crate::ascii::newline]: Matches a newline character `\n`
|
||||
//! - [`tab`][crate::ascii::tab]: Matches a tab character `\t`
|
||||
//!
|
||||
//! You can then capture sequences of these characters with parsers like [`take_while`].
|
||||
//! ```rust
|
||||
//! # use winnow::Parser;
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::token::take_while;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! take_while(1.., ('0'..='9', 'a'..='f', 'A'..='F')).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "1a2b Hello";
|
||||
//!
|
||||
//! let output = parse_digits.parse_next(&mut input).unwrap();
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(output, "1a2b");
|
||||
//!
|
||||
//! assert!(parse_digits.parse_next(&mut "Z").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! We could simplify this further by using one of the built-in character classes, [`hex_digit1`]:
|
||||
//! ```rust
|
||||
//! # use winnow::Parser;
|
||||
//! # use winnow::PResult;
|
||||
//! use winnow::ascii::hex_digit1;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! hex_digit1.parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "1a2b Hello";
|
||||
//!
|
||||
//! let output = parse_digits.parse_next(&mut input).unwrap();
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(output, "1a2b");
|
||||
//!
|
||||
//! assert!(parse_digits.parse_next(&mut "Z").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! See [`ascii`] for more text-based parsers.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use crate::ascii;
|
||||
use crate::ascii::hex_digit1;
|
||||
use crate::stream::ContainsToken;
|
||||
use crate::stream::Stream;
|
||||
use crate::token;
|
||||
use crate::token::any;
|
||||
use crate::token::one_of;
|
||||
use crate::token::tag;
|
||||
use crate::token::take_while;
|
||||
use crate::Parser;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
pub use super::chapter_1 as previous;
|
||||
pub use super::chapter_3 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
376
third-party/vendor/winnow/src/_tutorial/chapter_3.rs
vendored
Normal file
376
third-party/vendor/winnow/src/_tutorial/chapter_3.rs
vendored
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
//! # Chapter 3: Sequencing and Alternatives
|
||||
//!
|
||||
//! In the last chapter, we saw how to create simple parsers using prebuilt parsers.
|
||||
//!
|
||||
//! In this chapter, we explore two other widely used features:
|
||||
//! alternatives and composition.
|
||||
//!
|
||||
//! ## Sequencing
|
||||
//!
|
||||
//! Now that we can create more interesting parsers, we can sequence them together, like:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! #
|
||||
//! fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! "0x".parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! take_while(1.., (
|
||||
//! ('0'..='9'),
|
||||
//! ('A'..='F'),
|
||||
//! ('a'..='f'),
|
||||
//! )).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let prefix = parse_prefix.parse_next(&mut input).unwrap();
|
||||
//! let digits = parse_digits.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(prefix, "0x");
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! To sequence these together, you can just put them in a tuple:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! #
|
||||
//! # fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # "0x".parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! //...
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let (prefix, digits) = (
|
||||
//! parse_prefix,
|
||||
//! parse_digits
|
||||
//! ).parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(prefix, "0x");
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Frequently, you won't care about the tag and you can instead use one of the provided combinators,
|
||||
//! like [`preceded`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::preceded;
|
||||
//!
|
||||
//! # fn parse_prefix<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # "0x".parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! //...
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let digits = preceded(
|
||||
//! parse_prefix,
|
||||
//! parse_digits
|
||||
//! ).parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! See [`combinator`] for more sequencing parsers.
|
||||
//!
|
||||
//! ## Alternatives
|
||||
//!
|
||||
//! Sometimes, we might want to choose between two parsers; and we're happy with
|
||||
//! either being used.
|
||||
//!
|
||||
//! [`Stream::checkpoint`] helps us to retry parsing:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::stream::Stream;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
|
||||
//! let start = input.checkpoint();
|
||||
//!
|
||||
//! if let Ok(output) = ("0b", parse_bin_digits).parse_next(input) {
|
||||
//! return Ok(output);
|
||||
//! }
|
||||
//!
|
||||
//! input.reset(start);
|
||||
//! if let Ok(output) = ("0o", parse_oct_digits).parse_next(input) {
|
||||
//! return Ok(output);
|
||||
//! }
|
||||
//!
|
||||
//! input.reset(start);
|
||||
//! if let Ok(output) = ("0d", parse_dec_digits).parse_next(input) {
|
||||
//! return Ok(output);
|
||||
//! }
|
||||
//!
|
||||
//! input.reset(start);
|
||||
//! ("0x", parse_hex_digits).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(prefix, "0x");
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! > **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]
|
||||
//!
|
||||
//! [`opt`] is a basic building block for correctly handling retrying parsing:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::opt;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
|
||||
//! if let Some(output) = opt(("0b", parse_bin_digits)).parse_next(input)? {
|
||||
//! Ok(output)
|
||||
//! } else if let Some(output) = opt(("0o", parse_oct_digits)).parse_next(input)? {
|
||||
//! Ok(output)
|
||||
//! } else if let Some(output) = opt(("0d", parse_dec_digits)).parse_next(input)? {
|
||||
//! Ok(output)
|
||||
//! } else {
|
||||
//! ("0x", parse_hex_digits).parse_next(input)
|
||||
//! }
|
||||
//! }
|
||||
//! #
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # let mut input = "0x1a2b Hello";
|
||||
//! #
|
||||
//! # let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
|
||||
//! #
|
||||
//! # assert_eq!(input, " Hello");
|
||||
//! # assert_eq!(prefix, "0x");
|
||||
//! # assert_eq!(digits, "1a2b");
|
||||
//! #
|
||||
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! [`alt`] encapsulates this if/else-if ladder pattern, with the last case being the `else`:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::alt;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'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) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # let mut input = "0x1a2b Hello";
|
||||
//! #
|
||||
//! # let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
|
||||
//! #
|
||||
//! # assert_eq!(input, " Hello");
|
||||
//! # assert_eq!(prefix, "0x");
|
||||
//! # assert_eq!(digits, "1a2b");
|
||||
//! #
|
||||
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! > **Note:** [`empty`] and [`fail`] are parsers that might be useful in the `else` case.
|
||||
//!
|
||||
//! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for
|
||||
//! branches of your parser that have unique prefixes. In this case, you can use the
|
||||
//! [`dispatch`] macro:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::dispatch;
|
||||
//! use winnow::token::take;
|
||||
//! use winnow::combinator::fail;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! dispatch!(take(2usize);
|
||||
//! "0b" => parse_bin_digits,
|
||||
//! "0o" => parse_oct_digits,
|
||||
//! "0d" => parse_dec_digits,
|
||||
//! "0x" => parse_hex_digits,
|
||||
//! _ => fail,
|
||||
//! ).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let digits = parse_digits.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! > **Note:** [`peek`] may be useful when [`dispatch`]ing from hints from each case's parser.
|
||||
//!
|
||||
//! See [`combinator`] for more alternative parsers.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use super::chapter_6;
|
||||
use crate::combinator;
|
||||
use crate::combinator::alt;
|
||||
use crate::combinator::dispatch;
|
||||
use crate::combinator::empty;
|
||||
use crate::combinator::fail;
|
||||
use crate::combinator::opt;
|
||||
use crate::combinator::peek;
|
||||
use crate::combinator::preceded;
|
||||
use crate::stream::Stream;
|
||||
|
||||
pub use super::chapter_2 as previous;
|
||||
pub use super::chapter_4 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
107
third-party/vendor/winnow/src/_tutorial/chapter_4.rs
vendored
Normal file
107
third-party/vendor/winnow/src/_tutorial/chapter_4.rs
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
//! # Chapter 4: Parsers With Custom Return Types
|
||||
//!
|
||||
//! So far, we have seen mostly functions that take an `&str`, and return a
|
||||
//! `PResult<&str>`. Splitting strings into smaller strings and characters is certainly
|
||||
//! useful, but it's not the only thing winnow is capable of!
|
||||
//!
|
||||
//! A useful operation when parsing is to convert between types; for example
|
||||
//! parsing from `&str` to another primitive, like [`usize`].
|
||||
//!
|
||||
//! All we need to do for our parser to return a different type is to change
|
||||
//! the type parameter of [`PResult`] to the desired return type.
|
||||
//! For example, to return a `usize`, return a `PResult<usize>`.
|
||||
//!
|
||||
//! One winnow-native way of doing a type conversion is to use the
|
||||
//! [`Parser::parse_to`] combinator
|
||||
//! to convert from a successful parse to a particular type using [`FromStr`].
|
||||
//!
|
||||
//! The following code converts from a string containing a number to `usize`:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::ascii::digit1;
|
||||
//! #
|
||||
//! fn parse_digits(input: &mut &str) -> PResult<usize> {
|
||||
//! digit1
|
||||
//! .parse_to()
|
||||
//! .parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "1024 Hello";
|
||||
//!
|
||||
//! let output = parse_digits.parse_next(&mut input).unwrap();
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(output, 1024);
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "Z").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! `Parser::parse_to` is just a convenient form of [`Parser::try_map`] which we can use to handle
|
||||
//! all radices of numbers:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! use winnow::combinator::dispatch;
|
||||
//! use winnow::token::take;
|
||||
//! use winnow::combinator::fail;
|
||||
//!
|
||||
//! fn parse_digits(input: &mut &str) -> PResult<usize> {
|
||||
//! dispatch!(take(2usize);
|
||||
//! "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
|
||||
//! "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
|
||||
//! "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
|
||||
//! "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
|
||||
//! _ => fail,
|
||||
//! ).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let digits = parse_digits.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(digits, 0x1a2b);
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! See also [`Parser`] for more output-modifying parsers.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use crate::PResult;
|
||||
use crate::Parser;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use super::chapter_3 as previous;
|
||||
pub use super::chapter_5 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
282
third-party/vendor/winnow/src/_tutorial/chapter_5.rs
vendored
Normal file
282
third-party/vendor/winnow/src/_tutorial/chapter_5.rs
vendored
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
//! # Chapter 5: Repetition
|
||||
//!
|
||||
//! In [`chapter_3`], we covered how to sequence different parsers into a tuple but sometimes you need to run a
|
||||
//! single parser multiple times, collecting the result into a container, like [`Vec`].
|
||||
//!
|
||||
//! Let's collect the result of `parse_digits`:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # use winnow::token::take;
|
||||
//! # use winnow::combinator::fail;
|
||||
//! use winnow::combinator::opt;
|
||||
//! use winnow::combinator::repeat;
|
||||
//! use winnow::combinator::terminated;
|
||||
//!
|
||||
//! fn parse_list(input: &mut &str) -> PResult<Vec<usize>> {
|
||||
//! let mut list = Vec::new();
|
||||
//! while let Some(output) = opt(terminated(parse_digits, opt(','))).parse_next(input)? {
|
||||
//! list.push(output);
|
||||
//! }
|
||||
//! Ok(list)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<usize> {
|
||||
//! # dispatch!(take(2usize);
|
||||
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
|
||||
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
|
||||
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
|
||||
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
|
||||
//! # _ => fail,
|
||||
//! # ).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
|
||||
//!
|
||||
//! let digits = parse_list.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(digits, vec![0x1a2b, 0x3c4d, 0x5e6f]);
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! We can implement this declaratively with [`repeat`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # use winnow::token::take;
|
||||
//! # use winnow::combinator::fail;
|
||||
//! use winnow::combinator::opt;
|
||||
//! use winnow::combinator::repeat;
|
||||
//! use winnow::combinator::terminated;
|
||||
//!
|
||||
//! fn parse_list(input: &mut &str) -> PResult<Vec<usize>> {
|
||||
//! repeat(0..,
|
||||
//! terminated(parse_digits, opt(','))
|
||||
//! ).parse_next(input)
|
||||
//! }
|
||||
//! #
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<usize> {
|
||||
//! # dispatch!(take(2usize);
|
||||
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
|
||||
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
|
||||
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
|
||||
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
|
||||
//! # _ => fail,
|
||||
//! # ).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
|
||||
//! #
|
||||
//! # let digits = parse_list.parse_next(&mut input).unwrap();
|
||||
//! #
|
||||
//! # assert_eq!(input, " Hello");
|
||||
//! # assert_eq!(digits, vec![0x1a2b, 0x3c4d, 0x5e6f]);
|
||||
//! #
|
||||
//! # assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! You'll notice that the above allows trailing `,` when we intended to not support that. We can
|
||||
//! easily fix this by using [`separated`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # use winnow::token::take;
|
||||
//! # use winnow::combinator::fail;
|
||||
//! use winnow::combinator::separated;
|
||||
//!
|
||||
//! fn parse_list(input: &mut &str) -> PResult<Vec<usize>> {
|
||||
//! separated(0.., parse_digits, ",").parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<usize> {
|
||||
//! # dispatch!(take(2usize);
|
||||
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
|
||||
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
|
||||
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
|
||||
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
|
||||
//! # _ => fail,
|
||||
//! # ).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
|
||||
//!
|
||||
//! let digits = parse_list.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(digits, vec![0x1a2b, 0x3c4d, 0x5e6f]);
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! If you look closely at [`repeat`], it isn't collecting directly into a [`Vec`] but
|
||||
//! [`Accumulate`] to gather the results. This lets us make more complex parsers than we did in
|
||||
//! [`chapter_2`] by accumulating the results into a `()` and [`recognize`][Parser::recognize]-ing the captured input:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # use winnow::token::take;
|
||||
//! # use winnow::combinator::fail;
|
||||
//! # use winnow::combinator::separated;
|
||||
//! #
|
||||
//! fn recognize_list<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! parse_list.recognize().parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! fn parse_list(input: &mut &str) -> PResult<()> {
|
||||
//! separated(0.., parse_digits, ",").parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! # fn parse_digits(input: &mut &str) -> PResult<usize> {
|
||||
//! # dispatch!(take(2usize);
|
||||
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
|
||||
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
|
||||
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
|
||||
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
|
||||
//! # _ => fail,
|
||||
//! # ).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b,0x3c4d,0x5e6f Hello";
|
||||
//!
|
||||
//! let digits = recognize_list.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(digits, "0x1a2b,0x3c4d,0x5e6f");
|
||||
//!
|
||||
//! assert!(parse_digits(&mut "ghiWorld").is_err());
|
||||
//! }
|
||||
//! ```
|
||||
//! See [`combinator`] for more repetition parsers.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use super::chapter_2;
|
||||
use super::chapter_3;
|
||||
use crate::combinator;
|
||||
use crate::combinator::repeat;
|
||||
use crate::combinator::separated;
|
||||
use crate::stream::Accumulate;
|
||||
use crate::Parser;
|
||||
use std::vec::Vec;
|
||||
|
||||
pub use super::chapter_4 as previous;
|
||||
pub use super::chapter_6 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
156
third-party/vendor/winnow/src/_tutorial/chapter_6.rs
vendored
Normal file
156
third-party/vendor/winnow/src/_tutorial/chapter_6.rs
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
//! # Chapter 6: Error Reporting
|
||||
//!
|
||||
//! ## `Error`
|
||||
//!
|
||||
//! Back in [`chapter_1`], we glossed over the `Err` side of [`PResult`]. `PResult<O>` is
|
||||
//! actually short for `PResult<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 improve the error quality.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::alt;
|
||||
//! use winnow::error::StrContext;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
|
||||
//! alt((
|
||||
//! ("0b", parse_bin_digits).context(StrContext::Label("binary")),
|
||||
//! ("0o", parse_oct_digits).context(StrContext::Label("octal")),
|
||||
//! ("0d", parse_dec_digits).context(StrContext::Label("decimal")),
|
||||
//! ("0x", parse_hex_digits).context(StrContext::Label("hexadecimal")),
|
||||
//! )).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(prefix, "0x");
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! At first glance, this looks correct but what `context` will be reported when parsing `"0b5"`?
|
||||
//! If you remember back to [`chapter_3`], [`alt`] will only report the last error by default which
|
||||
//! means when parsing `"0b5"`, the `context` will be `"hexadecimal"`.
|
||||
//!
|
||||
//! ## `ErrMode`
|
||||
//!
|
||||
//! Let's break down `PResult<O, E>` one step further:
|
||||
//! ```rust
|
||||
//! # use winnow::error::ErrorKind;
|
||||
//! # use winnow::error::ErrMode;
|
||||
//! pub type PResult<O, E = ErrorKind> = Result<O, ErrMode<E>>;
|
||||
//! ```
|
||||
//! [`PResult`] is just a fancy wrapper around `Result` that wraps our error in an [`ErrMode`]
|
||||
//! type.
|
||||
//!
|
||||
//! [`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.
|
||||
//!
|
||||
//! So we can get the correct `context` by modifying the above example with [`cut_err`]:
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::alt;
|
||||
//! # use winnow::error::StrContext;
|
||||
//! use winnow::combinator::cut_err;
|
||||
//!
|
||||
//! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
|
||||
//! alt((
|
||||
//! ("0b", cut_err(parse_bin_digits)).context(StrContext::Label("binary")),
|
||||
//! ("0o", cut_err(parse_oct_digits)).context(StrContext::Label("octal")),
|
||||
//! ("0d", cut_err(parse_dec_digits)).context(StrContext::Label("decimal")),
|
||||
//! ("0x", cut_err(parse_hex_digits)).context(StrContext::Label("hexadecimal")),
|
||||
//! )).parse_next(input)
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut input = "0x1a2b Hello";
|
||||
//!
|
||||
//! let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
|
||||
//!
|
||||
//! assert_eq!(input, " Hello");
|
||||
//! assert_eq!(prefix, "0x");
|
||||
//! assert_eq!(digits, "1a2b");
|
||||
//! }
|
||||
//! ```
|
||||
//! Now, when parsing `"0b5"`, the `context` will be `"binary"`.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use super::chapter_1;
|
||||
use super::chapter_3;
|
||||
use crate::combinator::alt;
|
||||
use crate::combinator::cut_err;
|
||||
use crate::error::ContextError;
|
||||
use crate::error::ErrMode;
|
||||
use crate::error::ErrMode::*;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::PResult;
|
||||
use crate::Parser;
|
||||
use crate::_topic;
|
||||
|
||||
pub use super::chapter_5 as previous;
|
||||
pub use super::chapter_7 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
119
third-party/vendor/winnow/src/_tutorial/chapter_7.rs
vendored
Normal file
119
third-party/vendor/winnow/src/_tutorial/chapter_7.rs
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
//! # Chapter 7: Integrating the Parser
|
||||
//!
|
||||
//! So far, we've highlighted how to incrementally parse, but how do we bring this all together
|
||||
//! into our application?
|
||||
//!
|
||||
//! Parsers we've been working with look like:
|
||||
//! ```rust
|
||||
//! # use winnow::error::ContextError;
|
||||
//! # use winnow::error::ErrMode;
|
||||
//! # use winnow::Parser;
|
||||
//! #
|
||||
//! pub fn parser<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! // ...
|
||||
//! # Ok("")
|
||||
//! }
|
||||
//!
|
||||
//! type PResult<O> = Result<
|
||||
//! O,
|
||||
//! ErrMode<ContextError>
|
||||
//! >;
|
||||
//! ```
|
||||
//! 1. We have to decide what to do about the "remainder" of the `input`.
|
||||
//! 2. The [`ErrMode<ContextError>`] is not compatible with the rest of the Rust ecosystem.
|
||||
//! Normally, Rust applications want errors that are `std::error::Error + Send + Sync + 'static`
|
||||
//! meaning:
|
||||
//! - They implement the [`std::error::Error`] trait
|
||||
//! - They can be sent across threads
|
||||
//! - They are safe to be referenced across threads
|
||||
//! - They do not borrow
|
||||
//!
|
||||
//! winnow provides [`Parser::parse`] to help with this:
|
||||
//! - Ensures we hit [`eof`]
|
||||
//! - Removes the [`ErrMode`] wrapper
|
||||
//! - Wraps the error in [`ParseError`]
|
||||
//! - Provides access to the original [`input`][ParseError::input] with the
|
||||
//! [`offset`][ParseError::offset] of where it failed
|
||||
//! - Provides a default renderer (via [`std::fmt::Display`])
|
||||
//! ```rust
|
||||
//! # use winnow::prelude::*;
|
||||
//! # use winnow::token::take_while;
|
||||
//! # use winnow::combinator::dispatch;
|
||||
//! # 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
|
||||
//! .map(Hex)
|
||||
//! .parse(input)
|
||||
//! .map_err(|e| e.to_string())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//! # fn parse_digits<'s>(input: &mut &'s str) -> PResult<usize> {
|
||||
//! # dispatch!(take(2usize);
|
||||
//! # "0b" => parse_bin_digits.try_map(|s| usize::from_str_radix(s, 2)),
|
||||
//! # "0o" => parse_oct_digits.try_map(|s| usize::from_str_radix(s, 8)),
|
||||
//! # "0d" => parse_dec_digits.try_map(|s| usize::from_str_radix(s, 10)),
|
||||
//! # "0x" => parse_hex_digits.try_map(|s| usize::from_str_radix(s, 16)),
|
||||
//! # _ => fail,
|
||||
//! # ).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='7'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
|
||||
//! # take_while(1.., (
|
||||
//! # ('0'..='9'),
|
||||
//! # ('A'..='F'),
|
||||
//! # ('a'..='f'),
|
||||
//! # )).parse_next(input)
|
||||
//! # }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let input = "0x1a2b";
|
||||
//! assert_eq!(input.parse::<Hex>().unwrap(), Hex(0x1a2b));
|
||||
//!
|
||||
//! let input = "0x1a2b Hello";
|
||||
//! assert!(input.parse::<Hex>().is_err());
|
||||
//! let input = "ghiHello";
|
||||
//! assert!(input.parse::<Hex>().is_err());
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![allow(unused_imports)]
|
||||
use super::chapter_1;
|
||||
use crate::combinator::eof;
|
||||
use crate::error::ErrMode;
|
||||
use crate::error::InputError;
|
||||
use crate::error::ParseError;
|
||||
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;
|
||||
34
third-party/vendor/winnow/src/_tutorial/chapter_8.rs
vendored
Normal file
34
third-party/vendor/winnow/src/_tutorial/chapter_8.rs
vendored
Normal file
|
|
@ -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`:
|
||||
//! 
|
||||
//!
|
||||
//! You can extend your own parsers to show up by wrapping their body with
|
||||
//! [`trace`][crate::combinator::trace]. Going back to [`do_nothing_parser`][super::chapter_1].
|
||||
//! ```rust
|
||||
//! # use winnow::PResult;
|
||||
//! # use winnow::Parser;
|
||||
//! use winnow::combinator::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;
|
||||
14
third-party/vendor/winnow/src/_tutorial/mod.rs
vendored
Normal file
14
third-party/vendor/winnow/src/_tutorial/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//! # Tutorial
|
||||
//!
|
||||
//! Table of Contents
|
||||
#![allow(clippy::std_instead_of_core)]
|
||||
|
||||
pub mod chapter_0;
|
||||
pub mod chapter_1;
|
||||
pub mod chapter_2;
|
||||
pub mod chapter_3;
|
||||
pub mod chapter_4;
|
||||
pub mod chapter_5;
|
||||
pub mod chapter_6;
|
||||
pub mod chapter_7;
|
||||
pub mod chapter_8;
|
||||
Loading…
Add table
Add a link
Reference in a new issue