Skip to main content

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;