winnow/_tutorial/chapter_3.rs
1//! # Chapter 3: Sequencing and Alternatives
2//!
3//! In the last chapter, we saw how to create parsers using prebuilt parsers.
4//!
5//! In this chapter, we explore two other widely used features:
6//! sequencing and alternatives.
7//!
8//! ## Sequencing
9//!
10//! Now that we can create more interesting parsers, we can sequence them together, like:
11//!
12//! ```rust
13//! # use winnow::prelude::*;
14//! # use winnow::Result;
15//! # use winnow::token::take_while;
16//! #
17//! fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
18//! "0x".parse_next(input)
19//! }
20//!
21//! fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
22//! take_while(1.., (
23//! ('0'..='9'),
24//! ('A'..='F'),
25//! ('a'..='f'),
26//! )).parse_next(input)
27//! }
28//!
29//! fn main() {
30//! let mut input = "0x1a2b Hello";
31//!
32//! let prefix = parse_prefix.parse_next(&mut input).unwrap();
33//! let digits = parse_digits.parse_next(&mut input).unwrap();
34//!
35//! assert_eq!(prefix, "0x");
36//! assert_eq!(digits, "1a2b");
37//! assert_eq!(input, " Hello");
38//! }
39//! ```
40//!
41//! To sequence these together, you can just put them in a tuple:
42//! ```rust
43//! # use winnow::prelude::*;
44//! # use winnow::Result;
45//! # use winnow::token::take_while;
46//! #
47//! # fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
48//! # "0x".parse_next(input)
49//! # }
50//! #
51//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
52//! # take_while(1.., (
53//! # ('0'..='9'),
54//! # ('A'..='F'),
55//! # ('a'..='f'),
56//! # )).parse_next(input)
57//! # }
58//! #
59//! //...
60//!
61//! fn main() {
62//! let mut input = "0x1a2b Hello";
63//!
64//! let (prefix, digits) = (
65//! parse_prefix,
66//! parse_digits
67//! ).parse_next(&mut input).unwrap();
68//!
69//! assert_eq!(prefix, "0x");
70//! assert_eq!(digits, "1a2b");
71//! assert_eq!(input, " Hello");
72//! }
73//! ```
74//!
75//! Frequently, you won't care about the literal and you can instead use one of the provided combinators,
76//! like [`preceded`]:
77//! ```rust
78//! # use winnow::prelude::*;
79//! # use winnow::Result;
80//! # use winnow::token::take_while;
81//! use winnow::combinator::preceded;
82//!
83//! # fn parse_prefix<'s>(input: &mut &'s str) -> Result<&'s str> {
84//! # "0x".parse_next(input)
85//! # }
86//! #
87//! # fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
88//! # take_while(1.., (
89//! # ('0'..='9'),
90//! # ('A'..='F'),
91//! # ('a'..='f'),
92//! # )).parse_next(input)
93//! # }
94//! #
95//! //...
96//!
97//! fn main() {
98//! let mut input = "0x1a2b Hello";
99//!
100//! let digits = preceded(
101//! parse_prefix,
102//! parse_digits
103//! ).parse_next(&mut input).unwrap();
104//!
105//! assert_eq!(digits, "1a2b");
106//! assert_eq!(input, " Hello");
107//! }
108//! ```
109//!
110//! See [`combinator`] for more sequencing parsers.
111//!
112//! ## Alternatives
113//!
114//! Sometimes, we might want to choose between two parsers; and we're happy with
115//! either being used.
116//!
117//! To retry a parse result, we can save off a [`Stream::checkpoint`] and later restore the parser
118//! back to that position with [`Stream::reset`]:
119//! ```rust
120//! # use winnow::prelude::*;
121//! # use winnow::Result;
122//! # use winnow::token::take_while;
123//! use winnow::stream::Stream;
124//!
125//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
126//! let start = input.checkpoint();
127//! if let Ok(output) = ("0b", parse_bin_digits).parse_next(input) {
128//! return Ok(output);
129//! }
130//!
131//! input.reset(&start);
132//! if let Ok(output) = ("0o", parse_oct_digits).parse_next(input) {
133//! return Ok(output);
134//! }
135//!
136//! input.reset(&start);
137//! if let Ok(output) = ("0d", parse_dec_digits).parse_next(input) {
138//! return Ok(output);
139//! }
140//!
141//! input.reset(&start);
142//! ("0x", parse_hex_digits).parse_next(input)
143//! }
144//!
145//! // ...
146//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
147//! # take_while(1.., (
148//! # ('0'..='1'),
149//! # )).parse_next(input)
150//! # }
151//! #
152//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
153//! # take_while(1.., (
154//! # ('0'..='7'),
155//! # )).parse_next(input)
156//! # }
157//! #
158//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
159//! # take_while(1.., (
160//! # ('0'..='9'),
161//! # )).parse_next(input)
162//! # }
163//! #
164//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
165//! # take_while(1.., (
166//! # ('0'..='9'),
167//! # ('A'..='F'),
168//! # ('a'..='f'),
169//! # )).parse_next(input)
170//! # }
171//!
172//! fn main() {
173//! let mut input = "0x1a2b Hello";
174//!
175//! let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
176//!
177//! assert_eq!(input, " Hello");
178//! assert_eq!(prefix, "0x");
179//! assert_eq!(digits, "1a2b");
180//!
181//! assert!(parse_digits(&mut "ghiWorld").is_err());
182//! }
183//! ```
184//!
185//! <div class="warning">
186//!
187//! **Warning:** the above example is for illustrative purposes and relying on `Result::Ok` or
188//! `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering
189//! [error handling][`chapter_7`#error-cuts]
190//!
191//! </div>
192//!
193//! [`opt`] is a parser that encapsulates this pattern of "retry on failure":
194//! ```rust
195//! # use winnow::prelude::*;
196//! # use winnow::Result;
197//! # use winnow::token::take_while;
198//! use winnow::combinator::opt;
199//!
200//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
201//! if let Some(output) = opt(("0b", parse_bin_digits)).parse_next(input)? {
202//! Ok(output)
203//! } else if let Some(output) = opt(("0o", parse_oct_digits)).parse_next(input)? {
204//! Ok(output)
205//! } else if let Some(output) = opt(("0d", parse_dec_digits)).parse_next(input)? {
206//! Ok(output)
207//! } else {
208//! ("0x", parse_hex_digits).parse_next(input)
209//! }
210//! }
211//! #
212//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
213//! # take_while(1.., (
214//! # ('0'..='1'),
215//! # )).parse_next(input)
216//! # }
217//! #
218//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
219//! # take_while(1.., (
220//! # ('0'..='7'),
221//! # )).parse_next(input)
222//! # }
223//! #
224//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
225//! # take_while(1.., (
226//! # ('0'..='9'),
227//! # )).parse_next(input)
228//! # }
229//! #
230//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
231//! # take_while(1.., (
232//! # ('0'..='9'),
233//! # ('A'..='F'),
234//! # ('a'..='f'),
235//! # )).parse_next(input)
236//! # }
237//! #
238//! # fn main() {
239//! # let mut input = "0x1a2b Hello";
240//! #
241//! # let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
242//! #
243//! # assert_eq!(input, " Hello");
244//! # assert_eq!(prefix, "0x");
245//! # assert_eq!(digits, "1a2b");
246//! #
247//! # assert!(parse_digits(&mut "ghiWorld").is_err());
248//! # }
249//! ```
250//!
251//! [`alt`] encapsulates this if/else-if ladder pattern, with the last case being the "else":
252//! ```rust
253//! # use winnow::prelude::*;
254//! # use winnow::Result;
255//! # use winnow::token::take_while;
256//! use winnow::combinator::alt;
257//!
258//! fn parse_digits<'s>(input: &mut &'s str) -> Result<(&'s str, &'s str)> {
259//! alt((
260//! ("0b", parse_bin_digits),
261//! ("0o", parse_oct_digits),
262//! ("0d", parse_dec_digits),
263//! ("0x", parse_hex_digits),
264//! )).parse_next(input)
265//! }
266//! #
267//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
268//! # take_while(1.., (
269//! # ('0'..='1'),
270//! # )).parse_next(input)
271//! # }
272//! #
273//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
274//! # take_while(1.., (
275//! # ('0'..='7'),
276//! # )).parse_next(input)
277//! # }
278//! #
279//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
280//! # take_while(1.., (
281//! # ('0'..='9'),
282//! # )).parse_next(input)
283//! # }
284//! #
285//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
286//! # take_while(1.., (
287//! # ('0'..='9'),
288//! # ('A'..='F'),
289//! # ('a'..='f'),
290//! # )).parse_next(input)
291//! # }
292//! #
293//! # fn main() {
294//! # let mut input = "0x1a2b Hello";
295//! #
296//! # let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
297//! #
298//! # assert_eq!(input, " Hello");
299//! # assert_eq!(prefix, "0x");
300//! # assert_eq!(digits, "1a2b");
301//! #
302//! # assert!(parse_digits(&mut "ghiWorld").is_err());
303//! # }
304//! ```
305//!
306//! <div class="warning">
307//!
308//! **Note:** [`empty`] and [`fail`] are parsers that might be useful in the "else" case.
309//!
310//! </div>
311//!
312//! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for
313//! branches of your parser that have unique prefixes. In this case, you can use the
314//! [`dispatch`] macro:
315//!
316//! ```rust
317//! # use winnow::prelude::*;
318//! # use winnow::Result;
319//! # use winnow::token::take_while;
320//! use winnow::combinator::dispatch;
321//! use winnow::token::take;
322//! use winnow::combinator::fail;
323//!
324//! fn parse_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
325//! dispatch!(take(2usize);
326//! "0b" => parse_bin_digits,
327//! "0o" => parse_oct_digits,
328//! "0d" => parse_dec_digits,
329//! "0x" => parse_hex_digits,
330//! _ => fail,
331//! ).parse_next(input)
332//! }
333//! #
334//! # fn parse_bin_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
335//! # take_while(1.., (
336//! # ('0'..='1'),
337//! # )).parse_next(input)
338//! # }
339//! #
340//! # fn parse_oct_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
341//! # take_while(1.., (
342//! # ('0'..='7'),
343//! # )).parse_next(input)
344//! # }
345//! #
346//! # fn parse_dec_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
347//! # take_while(1.., (
348//! # ('0'..='9'),
349//! # )).parse_next(input)
350//! # }
351//! #
352//! # fn parse_hex_digits<'s>(input: &mut &'s str) -> Result<&'s str> {
353//! # take_while(1.., (
354//! # ('0'..='9'),
355//! # ('A'..='F'),
356//! # ('a'..='f'),
357//! # )).parse_next(input)
358//! # }
359//! #
360//! # fn main() {
361//! # let mut input = "0x1a2b Hello";
362//! #
363//! # let digits = parse_digits.parse_next(&mut input).unwrap();
364//! #
365//! # assert_eq!(input, " Hello");
366//! # assert_eq!(digits, "1a2b");
367//! #
368//! # assert!(parse_digits(&mut "ghiWorld").is_err());
369//! # }
370//! ```
371//!
372//! <div class="warning">
373//!
374//! **Note:** [`peek`] may be useful when [`dispatch`]ing from hints from each case's parser.
375//!
376//! </div>
377//!
378//! See [`combinator`] for more alternative parsers.
379
380#![allow(unused_imports)]
381use super::chapter_7;
382use crate::combinator;
383use crate::combinator::alt;
384use crate::combinator::dispatch;
385use crate::combinator::empty;
386use crate::combinator::fail;
387use crate::combinator::opt;
388use crate::combinator::peek;
389use crate::combinator::preceded;
390use crate::stream::Stream;
391
392pub use super::chapter_2 as previous;
393pub use super::chapter_4 as next;
394pub use crate::_tutorial as table_of_contents;