winnow/combinator/
core.rs

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