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