winnow/combinator/
branch.rs

1use crate::combinator::trace;
2use crate::error::{ErrMode, ErrorKind, ParserError};
3use crate::stream::Stream;
4use crate::*;
5
6#[doc(inline)]
7pub use crate::dispatch;
8
9/// Helper trait for the [`alt()`] combinator.
10///
11/// This trait is implemented for tuples of up to 21 elements
12pub trait Alt<I, O, E> {
13    /// Tests each parser in the tuple and returns the result of the first one that succeeds
14    fn choice(&mut self, input: &mut I) -> PResult<O, E>;
15}
16
17/// Pick the first successful parser
18///
19/// To stop on an error, rather than trying further cases, see
20/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_7]).
21///
22/// For tight control over the error when no match is found, add a final case using [`fail`][crate::combinator::fail].
23/// Alternatively, with a [custom error type][crate::_topic::error], it is possible to track all
24/// errors or return the error of the parser that went the farthest in the input data.
25///
26/// When the alternative cases have unique prefixes, [`dispatch`] can offer better performance.
27///
28/// # Example
29///
30/// ```rust
31/// # use winnow::{error::ErrMode, error::InputError,error::ErrorKind, error::Needed};
32/// # use winnow::prelude::*;
33/// use winnow::ascii::{alpha1, digit1};
34/// use winnow::combinator::alt;
35/// # fn main() {
36/// fn parser(input: &str) -> IResult<&str, &str> {
37///   alt((alpha1, digit1)).parse_peek(input)
38/// };
39///
40/// // the first parser, alpha1, takes the input
41/// assert_eq!(parser("abc"), Ok(("", "abc")));
42///
43/// // the first parser returns an error, so alt tries the second one
44/// assert_eq!(parser("123456"), Ok(("", "123456")));
45///
46/// // both parsers failed, and with the default error type, alt will return the last error
47/// assert_eq!(parser(" "), Err(ErrMode::Backtrack(InputError::new(" ", ErrorKind::Slice))));
48/// # }
49/// ```
50#[doc(alias = "choice")]
51#[inline(always)]
52pub fn alt<Input: Stream, Output, Error, Alternatives>(
53    mut alternatives: Alternatives,
54) -> impl Parser<Input, Output, Error>
55where
56    Alternatives: Alt<Input, Output, Error>,
57    Error: ParserError<Input>,
58{
59    trace("alt", move |i: &mut Input| alternatives.choice(i))
60}
61
62/// Helper trait for the [`permutation()`] combinator.
63///
64/// This trait is implemented for tuples of up to 21 elements
65pub trait Permutation<I, O, E> {
66    /// Tries to apply all parsers in the tuple in various orders until all of them succeed
67    fn permutation(&mut self, input: &mut I) -> PResult<O, E>;
68}
69
70/// Applies a list of parsers in any order.
71///
72/// Permutation will succeed if all of the child parsers succeeded.
73/// It takes as argument a tuple of parsers, and returns a
74/// tuple of the parser results.
75///
76/// To stop on an error, rather than trying further permutations, see
77/// [`cut_err`][crate::combinator::cut_err] ([example][crate::_tutorial::chapter_7]).
78///
79/// # Example
80///
81/// ```rust
82/// # use winnow::{error::ErrMode,error::{InputError, ErrorKind}, error::Needed};
83/// # use winnow::prelude::*;
84/// use winnow::ascii::{alpha1, digit1};
85/// use winnow::combinator::permutation;
86/// # fn main() {
87/// fn parser(input: &str) -> IResult<&str, (&str, &str)> {
88///   permutation((alpha1, digit1)).parse_peek(input)
89/// }
90///
91/// // permutation takes alphabetic characters then digit
92/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123"))));
93///
94/// // but also in inverse order
95/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123"))));
96///
97/// // it will fail if one of the parsers failed
98/// assert_eq!(parser("abc;"), Err(ErrMode::Backtrack(InputError::new(";", ErrorKind::Slice))));
99/// # }
100/// ```
101///
102/// The parsers are applied greedily: if there are multiple unapplied parsers
103/// that could parse the next slice of input, the first one is used.
104/// ```rust
105/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}};
106/// # use winnow::prelude::*;
107/// use winnow::combinator::permutation;
108/// use winnow::token::any;
109///
110/// fn parser(input: &str) -> IResult<&str, (char, char)> {
111///   permutation((any, 'a')).parse_peek(input)
112/// }
113///
114/// // any parses 'b', then char('a') parses 'a'
115/// assert_eq!(parser("ba"), Ok(("", ('b', 'a'))));
116///
117/// // any parses 'a', then char('a') fails on 'b',
118/// // even though char('a') followed by any would succeed
119/// assert_eq!(parser("ab"), Err(ErrMode::Backtrack(InputError::new("b", ErrorKind::Tag))));
120/// ```
121///
122#[inline(always)]
123pub fn permutation<I: Stream, O, E: ParserError<I>, List: Permutation<I, O, E>>(
124    mut l: List,
125) -> impl Parser<I, O, E> {
126    trace("permutation", move |i: &mut I| l.permutation(i))
127}
128
129impl<const N: usize, I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for [P; N] {
130    fn choice(&mut self, input: &mut I) -> PResult<O, E> {
131        let mut error: Option<E> = None;
132
133        let start = input.checkpoint();
134        for branch in self {
135            input.reset(&start);
136            match branch.parse_next(input) {
137                Err(ErrMode::Backtrack(e)) => {
138                    error = match error {
139                        Some(error) => Some(error.or(e)),
140                        None => Some(e),
141                    };
142                }
143                res => return res,
144            }
145        }
146
147        match error {
148            Some(e) => Err(ErrMode::Backtrack(e.append(input, &start, ErrorKind::Alt))),
149            None => Err(ErrMode::assert(input, "`alt` needs at least one parser")),
150        }
151    }
152}
153
154impl<I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for &mut [P] {
155    fn choice(&mut self, input: &mut I) -> PResult<O, E> {
156        let mut error: Option<E> = None;
157
158        let start = input.checkpoint();
159        for branch in self.iter_mut() {
160            input.reset(&start);
161            match branch.parse_next(input) {
162                Err(ErrMode::Backtrack(e)) => {
163                    error = match error {
164                        Some(error) => Some(error.or(e)),
165                        None => Some(e),
166                    };
167                }
168                res => return res,
169            }
170        }
171
172        match error {
173            Some(e) => Err(ErrMode::Backtrack(e.append(input, &start, ErrorKind::Alt))),
174            None => Err(ErrMode::assert(input, "`alt` needs at least one parser")),
175        }
176    }
177}
178
179macro_rules! alt_trait(
180  ($first:ident $second:ident $($id: ident)+) => (
181    alt_trait!(__impl $first $second; $($id)+);
182  );
183  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
184    alt_trait_impl!($($current)*);
185
186    alt_trait!(__impl $($current)* $head; $($id)+);
187  );
188  (__impl $($current:ident)*; $head:ident) => (
189    alt_trait_impl!($($current)*);
190    alt_trait_impl!($($current)* $head);
191  );
192);
193
194macro_rules! alt_trait_impl(
195  ($($id:ident)+) => (
196    impl<
197      I: Stream, Output, Error: ParserError<I>,
198      $($id: Parser<I, Output, Error>),+
199    > Alt<I, Output, Error> for ( $($id),+ ) {
200
201      fn choice(&mut self, input: &mut I) -> PResult<Output, Error> {
202        let start = input.checkpoint();
203        match self.0.parse_next(input) {
204          Err(ErrMode::Backtrack(e)) => alt_trait_inner!(1, self, input, start, e, $($id)+),
205          res => res,
206        }
207      }
208    }
209  );
210);
211
212macro_rules! succ (
213  (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
214  (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
215  (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
216  (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
217  (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
218  (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
219  (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
220  (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
221  (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
222  (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
223  (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
224  (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
225  (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
226  (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
227  (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
228  (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
229  (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
230  (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
231  (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
232  (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
233  (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
234);
235
236macro_rules! alt_trait_inner(
237  ($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident $($id:ident)+) => ({
238    $input.reset(&$start);
239    match $self.$it.parse_next($input) {
240      Err(ErrMode::Backtrack(e)) => {
241        let err = $err.or(e);
242        succ!($it, alt_trait_inner!($self, $input, $start, err, $($id)+))
243      }
244      res => res,
245    }
246  });
247  ($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident) => ({
248    Err(ErrMode::Backtrack($err.append($input, &$start, ErrorKind::Alt)))
249  });
250);
251
252alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10 Alt11 Alt12 Alt13 Alt14 Alt15 Alt16 Alt17 Alt18 Alt19 Alt20 Alt21 Alt22);
253
254// Manually implement Alt for (A,), the 1-tuple type
255impl<I: Stream, O, E: ParserError<I>, A: Parser<I, O, E>> Alt<I, O, E> for (A,) {
256    fn choice(&mut self, input: &mut I) -> PResult<O, E> {
257        self.0.parse_next(input)
258    }
259}
260
261macro_rules! permutation_trait(
262  (
263    $name1:ident $ty1:ident $item1:ident
264    $name2:ident $ty2:ident $item2:ident
265    $($name3:ident $ty3:ident $item3:ident)*
266  ) => (
267    permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*);
268  );
269  (
270    __impl $($name:ident $ty:ident $item:ident),+;
271    $name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)*
272  ) => (
273    permutation_trait_impl!($($name $ty $item),+);
274    permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*);
275  );
276  (__impl $($name:ident $ty:ident $item:ident),+;) => (
277    permutation_trait_impl!($($name $ty $item),+);
278  );
279);
280
281macro_rules! permutation_trait_impl(
282  ($($name:ident $ty:ident $item:ident),+) => (
283    impl<
284      I: Stream, $($ty),+ , Error: ParserError<I>,
285      $($name: Parser<I, $ty, Error>),+
286    > Permutation<I, ( $($ty),+ ), Error> for ( $($name),+ ) {
287
288      fn permutation(&mut self, input: &mut I) -> PResult<( $($ty),+ ), Error> {
289        let mut res = ($(Option::<$ty>::None),+);
290
291        loop {
292          let mut err: Option<Error> = None;
293          let start = input.checkpoint();
294          permutation_trait_inner!(0, self, input, start, res, err, $($name)+);
295
296          // If we reach here, every iterator has either been applied before,
297          // or errored on the remaining input
298          if let Some(err) = err {
299            // There are remaining parsers, and all errored on the remaining input
300            input.reset(&start);
301            return Err(ErrMode::Backtrack(err.append(input, &start, ErrorKind::Alt)));
302          }
303
304          // All parsers were applied
305          match res {
306            ($(Some($item)),+) => return Ok(($($item),+)),
307            _ => unreachable!(),
308          }
309        }
310      }
311    }
312  );
313);
314
315macro_rules! permutation_trait_inner(
316  ($it:tt, $self:expr, $input:ident, $start:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => (
317    if $res.$it.is_none() {
318      $input.reset(&$start);
319      match $self.$it.parse_next($input) {
320        Ok(o) => {
321          $res.$it = Some(o);
322          continue;
323        }
324        Err(ErrMode::Backtrack(e)) => {
325          $err = Some(match $err {
326            Some(err) => err.or(e),
327            None => e,
328          });
329        }
330        Err(e) => return Err(e),
331      };
332    }
333    succ!($it, permutation_trait_inner!($self, $input, $start, $res, $err, $($id)*));
334  );
335  ($it:tt, $self:expr, $input:ident, $start:ident, $res:expr, $err:expr,) => ();
336);
337
338permutation_trait!(
339  P1 O1 o1
340  P2 O2 o2
341  P3 O3 o3
342  P4 O4 o4
343  P5 O5 o5
344  P6 O6 o6
345  P7 O7 o7
346  P8 O8 o8
347  P9 O9 o9
348  P10 O10 o10
349  P11 O11 o11
350  P12 O12 o12
351  P13 O13 o13
352  P14 O14 o14
353  P15 O15 o15
354  P16 O16 o16
355  P17 O17 o17
356  P18 O18 o18
357  P19 O19 o19
358  P20 O20 o20
359  P21 O21 o21
360);