1 | use crate::combinator::trace; |
2 | use crate::error::{ModalError, ParserError}; |
3 | use crate::stream::Stream; |
4 | use crate::*; |
5 | |
6 | /// Apply a [`Parser`], producing `None` on [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack]. |
7 | /// |
8 | /// To chain an error up, see [`cut_err`]. |
9 | /// |
10 | /// # Example |
11 | /// |
12 | /// ```rust |
13 | /// # use winnow::prelude::*; |
14 | /// use winnow::combinator::opt; |
15 | /// use winnow::ascii::alpha1; |
16 | /// # fn main() { |
17 | /// |
18 | /// fn parser<'i>(i: &mut &'i str) -> ModalResult<Option<&'i str>> { |
19 | /// opt(alpha1).parse_next(i) |
20 | /// } |
21 | /// |
22 | /// assert_eq!(parser.parse_peek("abcd;" ), Ok((";" , Some("abcd" )))); |
23 | /// assert_eq!(parser.parse_peek("123;" ), Ok(("123;" , None))); |
24 | /// # } |
25 | /// ``` |
26 | pub fn opt<Input: Stream, Output, Error, ParseNext>( |
27 | mut parser: ParseNext, |
28 | ) -> impl Parser<Input, Option<Output>, Error> |
29 | where |
30 | ParseNext: Parser<Input, Output, Error>, |
31 | Error: ParserError<Input>, |
32 | { |
33 | trace(name:"opt" , parser:move |input: &mut Input| { |
34 | let start: ::Checkpoint = input.checkpoint(); |
35 | match parser.parse_next(input) { |
36 | Ok(o: Output) => Ok(Some(o)), |
37 | Err(e: Error) if e.is_backtrack() => { |
38 | input.reset(&start); |
39 | Ok(None) |
40 | } |
41 | Err(e: Error) => Err(e), |
42 | } |
43 | }) |
44 | } |
45 | |
46 | /// Calls the parser if the condition is met. |
47 | /// |
48 | /// # Example |
49 | /// |
50 | /// ```rust |
51 | /// # use winnow::prelude::*; |
52 | /// # use winnow::combinator::opt; |
53 | /// use winnow::combinator::cond; |
54 | /// use winnow::ascii::alpha1; |
55 | /// # fn main() { |
56 | /// |
57 | /// fn parser<'i>(i: &mut &'i str) -> ModalResult<Option<&'i str>> { |
58 | /// let prefix = opt("-" ).parse_next(i)?; |
59 | /// let condition = prefix.is_some(); |
60 | /// cond(condition, alpha1).parse_next(i) |
61 | /// } |
62 | /// |
63 | /// assert_eq!(parser.parse_peek("-abcd;" ), Ok((";" , Some("abcd" )))); |
64 | /// assert_eq!(parser.parse_peek("abcd;" ), Ok(("abcd;" , None))); |
65 | /// assert!(parser.parse_peek("-123;" ).is_err()); |
66 | /// assert_eq!(parser.parse_peek("123;" ), Ok(("123;" , None))); |
67 | /// # } |
68 | /// ``` |
69 | pub fn cond<Input, Output, Error, ParseNext>( |
70 | cond: bool, |
71 | mut parser: ParseNext, |
72 | ) -> impl Parser<Input, Option<Output>, Error> |
73 | where |
74 | Input: Stream, |
75 | ParseNext: Parser<Input, Output, Error>, |
76 | Error: ParserError<Input>, |
77 | { |
78 | trace(name:"cond" , parser:move |input: &mut Input| { |
79 | if cond { |
80 | parser.parse_next(input).map(op:Some) |
81 | } else { |
82 | Ok(None) |
83 | } |
84 | }) |
85 | } |
86 | |
87 | /// Apply the parser without advancing the input. |
88 | /// |
89 | /// To lookahead and only advance on success, see [`opt`]. |
90 | /// |
91 | /// # Example |
92 | /// |
93 | /// ```rust |
94 | /// # use winnow::prelude::*; |
95 | /// use winnow::combinator::peek; |
96 | /// use winnow::ascii::alpha1; |
97 | /// # fn main() { |
98 | /// |
99 | /// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> { |
100 | /// peek(alpha1).parse_next(input) |
101 | /// } |
102 | /// |
103 | /// assert_eq!(parser.parse_peek("abcd;" ), Ok(("abcd;" , "abcd" ))); |
104 | /// assert!(parser.parse_peek("123;" ).is_err()); |
105 | /// # } |
106 | /// ``` |
107 | #[doc (alias = "look_ahead" )] |
108 | #[doc (alias = "rewind" )] |
109 | pub fn peek<Input, Output, Error, ParseNext>( |
110 | mut parser: ParseNext, |
111 | ) -> impl Parser<Input, Output, Error> |
112 | where |
113 | Input: Stream, |
114 | Error: ParserError<Input>, |
115 | ParseNext: Parser<Input, Output, Error>, |
116 | { |
117 | trace(name:"peek" , parser:move |input: &mut Input| { |
118 | let start: ::Checkpoint = input.checkpoint(); |
119 | let res: Result = parser.parse_next(input); |
120 | input.reset(&start); |
121 | res |
122 | }) |
123 | } |
124 | |
125 | /// Match the end of the [`Stream`] |
126 | /// |
127 | /// Otherwise, it will error. |
128 | /// |
129 | /// # Effective Signature |
130 | /// |
131 | /// Assuming you are parsing a `&str` [Stream]: |
132 | /// ```rust |
133 | /// # use winnow::prelude::*;; |
134 | /// pub fn eof<'i>(input: &mut &'i str) -> ModalResult<&'i str> |
135 | /// # { |
136 | /// # winnow::combinator::eof.parse_next(input) |
137 | /// # } |
138 | /// ``` |
139 | /// |
140 | /// # Example |
141 | /// |
142 | /// ```rust |
143 | /// # use std::str; |
144 | /// # use winnow::combinator::eof; |
145 | /// # use winnow::prelude::*; |
146 | /// |
147 | /// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> { |
148 | /// eof.parse_next(input) |
149 | /// } |
150 | /// assert!(parser.parse_peek("abc" ).is_err()); |
151 | /// assert_eq!(parser.parse_peek("" ), Ok(("" , "" ))); |
152 | /// ``` |
153 | #[doc (alias = "end" )] |
154 | #[doc (alias = "eoi" )] |
155 | pub fn eof<Input, Error>(input: &mut Input) -> Result<<Input as Stream>::Slice, Error> |
156 | where |
157 | Input: Stream, |
158 | Error: ParserError<Input>, |
159 | { |
160 | traceimpl Parser::Slice, …>(name:"eof" , parser:move |input: &mut Input| { |
161 | if input.eof_offset() == 0 { |
162 | Ok(input.next_slice(offset:0)) |
163 | } else { |
164 | Err(ParserError::from_input(input)) |
165 | } |
166 | }) |
167 | .parse_next(input) |
168 | } |
169 | |
170 | /// Succeeds if the child parser returns an error. |
171 | /// |
172 | /// <div class="warning"> |
173 | /// |
174 | /// **Note:** This does not advance the [`Stream`] |
175 | /// |
176 | /// </div> |
177 | /// |
178 | /// # Example |
179 | /// |
180 | /// ```rust |
181 | /// # use winnow::prelude::*; |
182 | /// use winnow::combinator::not; |
183 | /// use winnow::ascii::alpha1; |
184 | /// # fn main() { |
185 | /// |
186 | /// fn parser<'i>(input: &mut &'i str) -> ModalResult<()> { |
187 | /// not(alpha1).parse_next(input) |
188 | /// } |
189 | /// |
190 | /// assert_eq!(parser.parse_peek("123" ), Ok(("123" , ()))); |
191 | /// assert!(parser.parse_peek("abcd" ).is_err()); |
192 | /// # } |
193 | /// ``` |
194 | pub fn not<Input, Output, Error, ParseNext>(mut parser: ParseNext) -> impl Parser<Input, (), Error> |
195 | where |
196 | Input: Stream, |
197 | Error: ParserError<Input>, |
198 | ParseNext: Parser<Input, Output, Error>, |
199 | { |
200 | trace(name:"not" , parser:move |input: &mut Input| { |
201 | let start: ::Checkpoint = input.checkpoint(); |
202 | let res: Result = parser.parse_next(input); |
203 | input.reset(&start); |
204 | match res { |
205 | Ok(_) => Err(ParserError::from_input(input)), |
206 | Err(e: Error) if e.is_backtrack() => Ok(()), |
207 | Err(e: Error) => Err(e), |
208 | } |
209 | }) |
210 | } |
211 | |
212 | /// Transforms an [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack] (recoverable) to [`ErrMode::Cut`][crate::error::ErrMode::Cut] (unrecoverable) |
213 | /// |
214 | /// This commits the parse result, preventing alternative branch paths like with |
215 | /// [`winnow::combinator::alt`][crate::combinator::alt]. |
216 | /// |
217 | /// See the [tutorial][crate::_tutorial::chapter_7] for more details. |
218 | /// |
219 | /// # Example |
220 | /// |
221 | /// Without `cut_err`: |
222 | /// ```rust |
223 | /// # use winnow::token::one_of; |
224 | /// # use winnow::token::rest; |
225 | /// # use winnow::ascii::digit1; |
226 | /// # use winnow::combinator::alt; |
227 | /// # use winnow::combinator::preceded; |
228 | /// # use winnow::prelude::*; |
229 | /// # fn main() { |
230 | /// |
231 | /// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> { |
232 | /// alt(( |
233 | /// preceded(one_of(['+' , '-' ]), digit1), |
234 | /// rest |
235 | /// )).parse_next(input) |
236 | /// } |
237 | /// |
238 | /// assert_eq!(parser.parse_peek("+10 ab" ), Ok((" ab" , "10" ))); |
239 | /// assert_eq!(parser.parse_peek("ab" ), Ok(("" , "ab" ))); |
240 | /// assert_eq!(parser.parse_peek("+" ), Ok(("" , "+" ))); |
241 | /// # } |
242 | /// ``` |
243 | /// |
244 | /// With `cut_err`: |
245 | /// ```rust |
246 | /// # use winnow::{error::ErrMode, error::ContextError}; |
247 | /// # use winnow::prelude::*; |
248 | /// # use winnow::token::one_of; |
249 | /// # use winnow::token::rest; |
250 | /// # use winnow::ascii::digit1; |
251 | /// # use winnow::combinator::alt; |
252 | /// # use winnow::combinator::preceded; |
253 | /// use winnow::combinator::cut_err; |
254 | /// # fn main() { |
255 | /// |
256 | /// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> { |
257 | /// alt(( |
258 | /// preceded(one_of(['+' , '-' ]), cut_err(digit1)), |
259 | /// rest |
260 | /// )).parse_next(input) |
261 | /// } |
262 | /// |
263 | /// assert_eq!(parser.parse_peek("+10 ab" ), Ok((" ab" , "10" ))); |
264 | /// assert_eq!(parser.parse_peek("ab" ), Ok(("" , "ab" ))); |
265 | /// assert_eq!(parser.parse_peek("+" ), Err(ErrMode::Cut(ContextError::new()))); |
266 | /// # } |
267 | /// ``` |
268 | pub fn cut_err<Input, Output, Error, ParseNext>( |
269 | mut parser: ParseNext, |
270 | ) -> impl Parser<Input, Output, Error> |
271 | where |
272 | Input: Stream, |
273 | Error: ParserError<Input> + ModalError, |
274 | ParseNext: Parser<Input, Output, Error>, |
275 | { |
276 | trace(name:"cut_err" , parser:move |input: &mut Input| { |
277 | parser.parse_next(input).map_err(|e: Error| e.cut()) |
278 | }) |
279 | } |
280 | |
281 | /// Transforms an [`ErrMode::Cut`][crate::error::ErrMode::Cut] (unrecoverable) to [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack] (recoverable) |
282 | /// |
283 | /// This attempts the parse, allowing other parsers to be tried on failure, like with |
284 | /// [`winnow::combinator::alt`][crate::combinator::alt]. |
285 | pub fn backtrack_err<Input, Output, Error, ParseNext>( |
286 | mut parser: ParseNext, |
287 | ) -> impl Parser<Input, Output, Error> |
288 | where |
289 | Input: Stream, |
290 | Error: ParserError<Input> + ModalError, |
291 | ParseNext: Parser<Input, Output, Error>, |
292 | { |
293 | trace(name:"backtrack_err" , parser:move |input: &mut Input| { |
294 | parser.parse_next(input).map_err(|e: Error| e.backtrack()) |
295 | }) |
296 | } |
297 | |
298 | /// A placeholder for a not-yet-implemented [`Parser`] |
299 | /// |
300 | /// This is analogous to the [`todo!`] macro and helps with prototyping. |
301 | /// |
302 | /// # Panic |
303 | /// |
304 | /// This will panic when parsing |
305 | /// |
306 | /// # Example |
307 | /// |
308 | /// ```rust |
309 | /// # use winnow::prelude::*; |
310 | /// # use winnow::combinator::todo; |
311 | /// |
312 | /// fn parser(input: &mut &str) -> ModalResult<u64> { |
313 | /// todo(input) |
314 | /// } |
315 | /// ``` |
316 | #[track_caller ] |
317 | pub fn todo<Input, Output, Error>(input: &mut Input) -> Result<Output, Error> |
318 | where |
319 | Input: Stream, |
320 | Error: ParserError<Input>, |
321 | { |
322 | #![allow (clippy::todo)] |
323 | traceimpl Parser(name:"todo" , parser:move |_input: &mut Input| { |
324 | todo!("unimplemented parse" ) |
325 | }) |
326 | .parse_next(input) |
327 | } |
328 | |
329 | /// Repeats the embedded parser, lazily returning the results |
330 | /// |
331 | /// Call the iterator's [`ParserIterator::finish`] method to get the remaining input if successful, |
332 | /// or the error value if we encountered an error. |
333 | /// |
334 | /// On [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack], iteration will stop. To instead chain an error up, see [`cut_err`]. |
335 | /// |
336 | /// # Example |
337 | /// |
338 | /// ```rust |
339 | /// # use winnow::prelude::*; |
340 | /// use winnow::{combinator::iterator, ascii::alpha1, combinator::terminated}; |
341 | /// use std::collections::HashMap; |
342 | /// |
343 | /// let data = "abc|defg|hijkl|mnopqr|123" ; |
344 | /// let mut it = iterator(data, terminated(alpha1, "|" )); |
345 | /// |
346 | /// let parsed = it.map(|v| (v, v.len())).collect::<HashMap<_,_>>(); |
347 | /// let res: ModalResult<_> = it.finish(); |
348 | /// |
349 | /// assert_eq!(parsed, [("abc" , 3usize), ("defg" , 4), ("hijkl" , 5), ("mnopqr" , 6)].iter().cloned().collect()); |
350 | /// assert_eq!(res, Ok(("123" , ()))); |
351 | /// ``` |
352 | pub fn iterator<Input, Output, Error, ParseNext>( |
353 | input: Input, |
354 | parser: ParseNext, |
355 | ) -> ParserIterator<ParseNext, Input, Output, Error> |
356 | where |
357 | ParseNext: Parser<Input, Output, Error>, |
358 | Input: Stream, |
359 | Error: ParserError<Input>, |
360 | { |
361 | ParserIterator { |
362 | parser, |
363 | input, |
364 | state: State::Running, |
365 | o: Default::default(), |
366 | } |
367 | } |
368 | |
369 | /// Main structure associated to [`iterator`]. |
370 | pub struct ParserIterator<F, I, O, E> |
371 | where |
372 | F: Parser<I, O, E>, |
373 | I: Stream, |
374 | { |
375 | parser: F, |
376 | input: I, |
377 | state: State<E>, |
378 | o: core::marker::PhantomData<O>, |
379 | } |
380 | |
381 | impl<F, I, O, E> ParserIterator<F, I, O, E> |
382 | where |
383 | F: Parser<I, O, E>, |
384 | I: Stream, |
385 | E: ParserError<I>, |
386 | { |
387 | /// Returns the remaining input if parsing was successful, or the error if we encountered an error. |
388 | pub fn finish(self) -> Result<(I, ()), E> { |
389 | match self.state { |
390 | State::Running | State::Done => Ok((self.input, ())), |
391 | State::Cut(e: E) => Err(e), |
392 | } |
393 | } |
394 | } |
395 | |
396 | impl<F, I, O, E> core::iter::Iterator for &mut ParserIterator<F, I, O, E> |
397 | where |
398 | F: Parser<I, O, E>, |
399 | I: Stream, |
400 | E: ParserError<I>, |
401 | { |
402 | type Item = O; |
403 | |
404 | fn next(&mut self) -> Option<Self::Item> { |
405 | if matches!(self.state, State::Running) { |
406 | let start = self.input.checkpoint(); |
407 | |
408 | match self.parser.parse_next(&mut self.input) { |
409 | Ok(o) => { |
410 | self.state = State::Running; |
411 | Some(o) |
412 | } |
413 | Err(e) if e.is_backtrack() => { |
414 | self.input.reset(&start); |
415 | self.state = State::Done; |
416 | None |
417 | } |
418 | Err(e) => { |
419 | self.state = State::Cut(e); |
420 | None |
421 | } |
422 | } |
423 | } else { |
424 | None |
425 | } |
426 | } |
427 | } |
428 | |
429 | enum State<E> { |
430 | Running, |
431 | Done, |
432 | Cut(E), |
433 | } |
434 | |
435 | /// Succeed, consuming no input |
436 | /// |
437 | /// For example, it can be used as the last alternative in `alt` to |
438 | /// specify the default case. |
439 | /// |
440 | /// Useful with: |
441 | /// - [`Parser::value`] |
442 | /// - [`Parser::default_value`] |
443 | /// - [`Parser::map`] |
444 | /// |
445 | /// <div class="warning"> |
446 | /// |
447 | /// **Note:** This never advances the [`Stream`] |
448 | /// |
449 | /// </div> |
450 | /// |
451 | /// # Example |
452 | /// |
453 | /// ```rust |
454 | /// # use winnow::prelude::*; |
455 | /// use winnow::combinator::alt; |
456 | /// use winnow::combinator::empty; |
457 | /// |
458 | /// fn sign(input: &mut &str) -> ModalResult<isize> { |
459 | /// alt(( |
460 | /// '-' .value(-1), |
461 | /// '+' .value(1), |
462 | /// empty.value(1) |
463 | /// )).parse_next(input) |
464 | /// } |
465 | /// assert_eq!(sign.parse_peek("+10" ), Ok(("10" , 1))); |
466 | /// assert_eq!(sign.parse_peek("-10" ), Ok(("10" , -1))); |
467 | /// assert_eq!(sign.parse_peek("10" ), Ok(("10" , 1))); |
468 | /// ``` |
469 | #[doc (alias = "value" )] |
470 | #[doc (alias = "success" )] |
471 | #[inline ] |
472 | pub fn empty<Input, Error>(_input: &mut Input) -> Result<(), Error> |
473 | where |
474 | Input: Stream, |
475 | Error: ParserError<Input>, |
476 | { |
477 | Ok(()) |
478 | } |
479 | |
480 | /// A parser which always fails. |
481 | /// |
482 | /// For example, it can be used as the last alternative in `alt` to |
483 | /// control the error message given. |
484 | /// |
485 | /// # Example |
486 | /// |
487 | /// ```rust |
488 | /// # use winnow::{error::ErrMode, error::InputError}; |
489 | /// # use winnow::prelude::*; |
490 | /// use winnow::combinator::fail; |
491 | /// |
492 | /// fn parser<'i>(input: &mut &'i str) -> ModalResult<(), InputError<&'i str>> { |
493 | /// fail.parse_next(input) |
494 | /// } |
495 | /// |
496 | /// assert_eq!(parser.parse_peek("string" ), Err(ErrMode::Backtrack(InputError::at("string" )))); |
497 | /// ``` |
498 | #[doc (alias = "unexpected" )] |
499 | #[inline ] |
500 | pub fn fail<Input, Output, Error>(i: &mut Input) -> Result<Output, Error> |
501 | where |
502 | Input: Stream, |
503 | Error: ParserError<Input>, |
504 | { |
505 | trace("fail" , |i: &mut Input| Err(ParserError::from_input(i))).parse_next(input:i) |
506 | } |
507 | |