• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::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 literal 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 //! To retry a parse result, we can save off a [`Stream::checkpoint`] and later restore the parser
115 //! back to that position with [`Stream::reset`]:
116 //! ```rust
117 //! # use winnow::prelude::*;
118 //! # use winnow::token::take_while;
119 //! use winnow::stream::Stream;
120 //!
121 //! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
122 //!     let start = input.checkpoint();
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'..='1'),
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 //! <div class="warning">
182 //!
183 //! **Warning:** the above example is for illustrative purposes and relying on `Result::Ok` or
184 //! `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering
185 //! [error handling][`chapter_7`#error-cuts]
186 //!
187 //! </div>
188 //!
189 //! [`opt`] is a parser that encapsulates this pattern of "retry on failure":
190 //! ```rust
191 //! # use winnow::prelude::*;
192 //! # use winnow::token::take_while;
193 //! use winnow::combinator::opt;
194 //!
195 //! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
196 //!     if let Some(output) = opt(("0b", parse_bin_digits)).parse_next(input)? {
197 //!         Ok(output)
198 //!     } else if let Some(output) = opt(("0o", parse_oct_digits)).parse_next(input)? {
199 //!         Ok(output)
200 //!     } else if let Some(output) = opt(("0d", parse_dec_digits)).parse_next(input)? {
201 //!         Ok(output)
202 //!     } else {
203 //!         ("0x", parse_hex_digits).parse_next(input)
204 //!     }
205 //! }
206 //! #
207 //! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
208 //! #     take_while(1.., (
209 //! #         ('0'..='1'),
210 //! #     )).parse_next(input)
211 //! # }
212 //! #
213 //! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
214 //! #     take_while(1.., (
215 //! #         ('0'..='7'),
216 //! #     )).parse_next(input)
217 //! # }
218 //! #
219 //! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
220 //! #     take_while(1.., (
221 //! #         ('0'..='9'),
222 //! #     )).parse_next(input)
223 //! # }
224 //! #
225 //! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
226 //! #     take_while(1.., (
227 //! #         ('0'..='9'),
228 //! #         ('A'..='F'),
229 //! #         ('a'..='f'),
230 //! #     )).parse_next(input)
231 //! # }
232 //! #
233 //! # fn main() {
234 //! #     let mut input = "0x1a2b Hello";
235 //! #
236 //! #     let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
237 //! #
238 //! #     assert_eq!(input, " Hello");
239 //! #     assert_eq!(prefix, "0x");
240 //! #     assert_eq!(digits, "1a2b");
241 //! #
242 //! #     assert!(parse_digits(&mut "ghiWorld").is_err());
243 //! # }
244 //! ```
245 //!
246 //! [`alt`] encapsulates this if/else-if ladder pattern, with the last case being the "else":
247 //! ```rust
248 //! # use winnow::prelude::*;
249 //! # use winnow::token::take_while;
250 //! use winnow::combinator::alt;
251 //!
252 //! fn parse_digits<'s>(input: &mut &'s str) -> PResult<(&'s str, &'s str)> {
253 //!     alt((
254 //!         ("0b", parse_bin_digits),
255 //!         ("0o", parse_oct_digits),
256 //!         ("0d", parse_dec_digits),
257 //!         ("0x", parse_hex_digits),
258 //!     )).parse_next(input)
259 //! }
260 //! #
261 //! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
262 //! #     take_while(1.., (
263 //! #         ('0'..='1'),
264 //! #     )).parse_next(input)
265 //! # }
266 //! #
267 //! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
268 //! #     take_while(1.., (
269 //! #         ('0'..='7'),
270 //! #     )).parse_next(input)
271 //! # }
272 //! #
273 //! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
274 //! #     take_while(1.., (
275 //! #         ('0'..='9'),
276 //! #     )).parse_next(input)
277 //! # }
278 //! #
279 //! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
280 //! #     take_while(1.., (
281 //! #         ('0'..='9'),
282 //! #         ('A'..='F'),
283 //! #         ('a'..='f'),
284 //! #     )).parse_next(input)
285 //! # }
286 //! #
287 //! # fn main() {
288 //! #     let mut input = "0x1a2b Hello";
289 //! #
290 //! #     let (prefix, digits) = parse_digits.parse_next(&mut input).unwrap();
291 //! #
292 //! #     assert_eq!(input, " Hello");
293 //! #     assert_eq!(prefix, "0x");
294 //! #     assert_eq!(digits, "1a2b");
295 //! #
296 //! #     assert!(parse_digits(&mut "ghiWorld").is_err());
297 //! # }
298 //! ```
299 //!
300 //! <div class="warning">
301 //!
302 //! **Note:** [`empty`] and [`fail`] are parsers that might be useful in the "else" case.
303 //!
304 //! </div>
305 //!
306 //! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for
307 //! branches of your parser that have unique prefixes. In this case, you can use the
308 //! [`dispatch`] macro:
309 //!
310 //! ```rust
311 //! # use winnow::prelude::*;
312 //! # use winnow::token::take_while;
313 //! use winnow::combinator::dispatch;
314 //! use winnow::token::take;
315 //! use winnow::combinator::fail;
316 //!
317 //! fn parse_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
318 //!     dispatch!(take(2usize);
319 //!         "0b" => parse_bin_digits,
320 //!         "0o" => parse_oct_digits,
321 //!         "0d" => parse_dec_digits,
322 //!         "0x" => parse_hex_digits,
323 //!         _ => fail,
324 //!     ).parse_next(input)
325 //! }
326 //! #
327 //! # fn parse_bin_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
328 //! #     take_while(1.., (
329 //! #         ('0'..='1'),
330 //! #     )).parse_next(input)
331 //! # }
332 //! #
333 //! # fn parse_oct_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
334 //! #     take_while(1.., (
335 //! #         ('0'..='7'),
336 //! #     )).parse_next(input)
337 //! # }
338 //! #
339 //! # fn parse_dec_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
340 //! #     take_while(1.., (
341 //! #         ('0'..='9'),
342 //! #     )).parse_next(input)
343 //! # }
344 //! #
345 //! # fn parse_hex_digits<'s>(input: &mut &'s str) -> PResult<&'s str> {
346 //! #     take_while(1.., (
347 //! #         ('0'..='9'),
348 //! #         ('A'..='F'),
349 //! #         ('a'..='f'),
350 //! #     )).parse_next(input)
351 //! # }
352 //! #
353 //! # fn main() {
354 //! #     let mut input = "0x1a2b Hello";
355 //! #
356 //! #     let digits = parse_digits.parse_next(&mut input).unwrap();
357 //! #
358 //! #     assert_eq!(input, " Hello");
359 //! #     assert_eq!(digits, "1a2b");
360 //! #
361 //! #     assert!(parse_digits(&mut "ghiWorld").is_err());
362 //! # }
363 //! ```
364 //!
365 //! <div class="warning">
366 //!
367 //! **Note:** [`peek`] may be useful when [`dispatch`]ing from hints from each case's parser.
368 //!
369 //! </div>
370 //!
371 //! See [`combinator`] for more alternative parsers.
372 
373 #![allow(unused_imports)]
374 use super::chapter_7;
375 use crate::combinator;
376 use crate::combinator::alt;
377 use crate::combinator::dispatch;
378 use crate::combinator::empty;
379 use crate::combinator::fail;
380 use crate::combinator::opt;
381 use crate::combinator::peek;
382 use crate::combinator::preceded;
383 use crate::stream::Stream;
384 
385 pub use super::chapter_2 as previous;
386 pub use super::chapter_4 as next;
387 pub use crate::_tutorial as table_of_contents;
388