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