blob: 29c5db4570e18e2b085c0e525b8692d8d43223c3 [file] [log] [blame]
//! # 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::bytes::take_while1;
//! # use winnow::Parser;
//! # use winnow::IResult;
//! #
//! fn parse_prefix(input: &str) -> IResult<&str, &str> {
//! "0x".parse_next(input)
//! }
//!
//! fn parse_digits(input: &str) -> IResult<&str, &str> {
//! take_while1((
//! ('0'..='9'),
//! ('A'..='F'),
//! ('a'..='f'),
//! )).parse_next(input)
//! }
//!
//! fn main() {
//! let input = "0x1a2b Hello";
//!
//! let (remainder, prefix) = parse_prefix.parse_next(input).unwrap();
//! let (remainder, digits) = parse_digits.parse_next(remainder).unwrap();
//!
//! assert_eq!(prefix, "0x");
//! assert_eq!(digits, "1a2b");
//! assert_eq!(remainder, " Hello");
//! }
//! ```
//!
//! To sequence these together, you can just put them in a tuple:
//! ```rust
//! # use winnow::bytes::take_while1;
//! # use winnow::Parser;
//! # use winnow::IResult;
//! #
//! # fn parse_prefix(input: &str) -> IResult<&str, &str> {
//! # "0x".parse_next(input)
//! # }
//! #
//! # fn parse_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! //...
//!
//! fn main() {
//! let input = "0x1a2b Hello";
//!
//! let (remainder, (prefix, digits)) = (
//! parse_prefix,
//! parse_digits
//! ).parse_next(input).unwrap();
//!
//! assert_eq!(prefix, "0x");
//! assert_eq!(digits, "1a2b");
//! assert_eq!(remainder, " Hello");
//! }
//! ```
//!
//! Frequently, you won't care about the tag and you can instead use one of the provided combinators,
//! like [`preceded`]:
//! ```rust
//! # use winnow::bytes::take_while1;
//! # use winnow::Parser;
//! # use winnow::IResult;
//! use winnow::sequence::preceded;
//!
//! # fn parse_prefix(input: &str) -> IResult<&str, &str> {
//! # "0x".parse_next(input)
//! # }
//! #
//! # fn parse_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//! #
//! //...
//!
//! fn main() {
//! let input = "0x1a2b Hello";
//!
//! let (remainder, digits) = preceded(
//! parse_prefix,
//! parse_digits
//! ).parse_next(input).unwrap();
//!
//! assert_eq!(digits, "1a2b");
//! assert_eq!(remainder, " Hello");
//! }
//! ```
//!
//! ## Alternatives
//!
//! Sometimes, we might want to choose between two parsers; and we're happy with
//! either being used.
//!
//! The de facto way to do this in winnow is with the [`alt()`] combinator which will execute each
//! parser in a tuple until it finds one that does not error. If all error, then by default you are
//! given the error from the last parser.
//!
//! We can see a basic example of `alt()` below.
//! ```rust
//! # use winnow::IResult;
//! # use winnow::Parser;
//! # use winnow::bytes::take_while1;
//! use winnow::branch::alt;
//!
//! fn parse_digits(input: &str) -> IResult<&str, (&str, &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(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let input = "0x1a2b Hello";
//!
//! let (remainder, (prefix, digits)) = parse_digits.parse_next(input).unwrap();
//!
//! assert_eq!(remainder, " Hello");
//! assert_eq!(prefix, "0x");
//! assert_eq!(digits, "1a2b");
//!
//! assert!(parse_digits("ghiWorld").is_err());
//! }
//! ```
//!
//! 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`][crate::branch::dispatch] macro:
//!
//! ```rust
//! # use winnow::IResult;
//! # use winnow::Parser;
//! # use winnow::bytes::take_while1;
//! use winnow::branch::dispatch;
//! use winnow::bytes::take;
//! use winnow::combinator::fail;
//!
//! fn parse_digits(input: &str) -> IResult<&str, &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(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_oct_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='7'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_dec_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='9'),
//! # )).parse_next(input)
//! # }
//! #
//! # fn parse_hex_digits(input: &str) -> IResult<&str, &str> {
//! # take_while1((
//! # ('0'..='9'),
//! # ('A'..='F'),
//! # ('a'..='f'),
//! # )).parse_next(input)
//! # }
//!
//! fn main() {
//! let input = "0x1a2b Hello";
//!
//! let (remainder, digits) = parse_digits.parse_next(input).unwrap();
//!
//! assert_eq!(remainder, " Hello");
//! assert_eq!(digits, "1a2b");
//!
//! assert!(parse_digits("ghiWorld").is_err());
//! }
//! ```
#![allow(unused_imports)]
use crate::branch::alt;
use crate::branch::dispatch;
use crate::sequence::preceded;
pub use super::chapter_2 as previous;
pub use super::chapter_4 as next;