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