Skip to main content

winnow/combinator/
branch.rs

1use crate::combinator::trace;
2use crate::error::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) -> Result<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::Needed};
32/// # use winnow::prelude::*;
33/// use winnow::ascii::{alpha1, digit1};
34/// use winnow::combinator::alt;
35/// # fn main() {
36/// fn parser<'i>(input: &mut &'i str) -> ModalResult<&'i str> {
37///   alt((alpha1, digit1)).parse_next(input)
38/// };
39///
40/// // the first parser, alpha1, takes the input
41/// assert_eq!(parser.parse_peek("abc"), Ok(("", "abc")));
42///
43/// // the first parser returns an error, so alt tries the second one
44/// assert_eq!(parser.parse_peek("123456"), Ok(("", "123456")));
45///
46/// // both parsers failed, and with the default error type, alt will return the last error
47/// assert!(parser.parse_peek(" ").is_err());
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) -> Result<O, E>;
68}
69
70/// Deprecated, replaced with [`unordered_seq!`][crate::combinator::unordered_seq].
71#[deprecated(since = "0.7.14", note = "replaced with `unordered_seq!`")]
72#[inline(always)]
73pub fn permutation<I: Stream, O, E: ParserError<I>, List: Permutation<I, O, E>>(
74    mut l: List,
75) -> impl Parser<I, O, E> {
76    trace("permutation", move |i: &mut I| l.permutation(i))
77}
78
79impl<const N: usize, I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for [P; N] {
80    fn choice(&mut self, input: &mut I) -> Result<O, E> {
81        let mut error: Option<E> = None;
82
83        let start = input.checkpoint();
84        for branch in self {
85            input.reset(&start);
86            match branch.parse_next(input) {
87                Err(e) if e.is_backtrack() => {
88                    error = match error {
89                        Some(error) => Some(error.or(e)),
90                        None => Some(e),
91                    };
92                }
93                res => return res,
94            }
95        }
96
97        match error {
98            Some(e) => Err(e.append(input, &start)),
99            None => Err(ParserError::assert(
100                input,
101                "`alt` needs at least one parser",
102            )),
103        }
104    }
105}
106
107impl<I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for &mut [P] {
108    fn choice(&mut self, input: &mut I) -> Result<O, E> {
109        let mut error: Option<E> = None;
110
111        let start = input.checkpoint();
112        for branch in self.iter_mut() {
113            input.reset(&start);
114            match branch.parse_next(input) {
115                Err(e) if e.is_backtrack() => {
116                    error = match error {
117                        Some(error) => Some(error.or(e)),
118                        None => Some(e),
119                    };
120                }
121                res => return res,
122            }
123        }
124
125        match error {
126            Some(e) => Err(e.append(input, &start)),
127            None => Err(ParserError::assert(
128                input,
129                "`alt` needs at least one parser",
130            )),
131        }
132    }
133}
134
135macro_rules! alt_trait(
136  ($first:ident $second:ident $($id: ident)+) => (
137    alt_trait!(__impl $first $second; $($id)+);
138  );
139  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
140    alt_trait_impl!($($current)*);
141
142    alt_trait!(__impl $($current)* $head; $($id)+);
143  );
144  (__impl $($current:ident)*; $head:ident) => (
145    alt_trait_impl!($($current)*);
146    alt_trait_impl!($($current)* $head);
147  );
148);
149
150macro_rules! alt_trait_impl(
151  ($($id:ident)+) => (
152    impl<
153      I: Stream, Output, Error: ParserError<I>,
154      $($id: Parser<I, Output, Error>),+
155    > Alt<I, Output, Error> for ( $($id),+ ) {
156
157      fn choice(&mut self, input: &mut I) -> Result<Output, Error> {
158        let start = input.checkpoint();
159        match self.0.parse_next(input) {
160          Err(e) if e.is_backtrack() => alt_trait_inner!(1, self, input, start, e, $($id)+),
161          res => res,
162        }
163      }
164    }
165  );
166);
167
168macro_rules! succ (
169    (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
170    (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
171    (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
172    (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
173    (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
174    (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
175    (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
176    (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
177    (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
178    (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
179    (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
180    (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
181    (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
182    (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
183    (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
184    (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
185    (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
186    (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
187    (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
188    (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
189    (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
190);
191
192macro_rules! alt_trait_inner(
193    ($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident $($id:ident)+) => ({
194        $input.reset(&$start);
195        match $self.$it.parse_next($input) {
196            Err(e) if e.is_backtrack() => {
197                let err = $err.or(e);
198                succ!($it, alt_trait_inner!($self, $input, $start, err, $($id)+))
199            }
200            res => res,
201        }
202    });
203    ($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident) => ({
204        Err($err.append($input, &$start))
205    });
206);
207
208alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10 Alt11 Alt12 Alt13 Alt14 Alt15 Alt16 Alt17 Alt18 Alt19 Alt20 Alt21 Alt22);
209
210// Manually implement Alt for (A,), the 1-tuple type
211impl<I: Stream, O, E: ParserError<I>, A: Parser<I, O, E>> Alt<I, O, E> for (A,) {
212    fn choice(&mut self, input: &mut I) -> Result<O, E> {
213        self.0.parse_next(input)
214    }
215}
216
217macro_rules! permutation_trait(
218  (
219    $name1:ident $ty1:ident $item1:ident
220    $name2:ident $ty2:ident $item2:ident
221    $($name3:ident $ty3:ident $item3:ident)*
222  ) => (
223    permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*);
224  );
225  (
226    __impl $($name:ident $ty:ident $item:ident),+;
227    $name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)*
228  ) => (
229    permutation_trait_impl!($($name $ty $item),+);
230    permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*);
231  );
232  (__impl $($name:ident $ty:ident $item:ident),+;) => (
233    permutation_trait_impl!($($name $ty $item),+);
234  );
235);
236
237macro_rules! permutation_trait_impl(
238  ($($name:ident $ty:ident $item:ident),+) => (
239    impl<
240      I: Stream, $($ty),+ , Error: ParserError<I>,
241      $($name: Parser<I, $ty, Error>),+
242    > Permutation<I, ( $($ty),+ ), Error> for ( $($name),+ ) {
243
244      fn permutation(&mut self, input: &mut I) -> Result<( $($ty),+ ), Error> {
245        let mut res = ($(Option::<$ty>::None),+);
246
247        loop {
248          let mut err: Option<Error> = None;
249          let start = input.checkpoint();
250          permutation_trait_inner!(0, self, input, start, res, err, $($name)+);
251
252          // If we reach here, every iterator has either been applied before,
253          // or errored on the remaining input
254          if let Some(err) = err {
255            // There are remaining parsers, and all errored on the remaining input
256            input.reset(&start);
257            return Err(err.append(input, &start));
258          }
259
260          // All parsers were applied
261          match res {
262            ($(Some($item)),+) => return Ok(($($item),+)),
263            _ => unreachable!(),
264          }
265        }
266      }
267    }
268  );
269);
270
271macro_rules! permutation_trait_inner(
272  ($it:tt, $self:expr, $input:ident, $start:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => (
273    if $res.$it.is_none() {
274      $input.reset(&$start);
275      match $self.$it.parse_next($input) {
276        Ok(o) => {
277          $res.$it = Some(o);
278          continue;
279        }
280        Err(e) if e.is_backtrack() => {
281          $err = Some(match $err {
282            Some(err) => err.or(e),
283            None => e,
284          });
285        }
286        Err(e) => return Err(e),
287      };
288    }
289    succ!($it, permutation_trait_inner!($self, $input, $start, $res, $err, $($id)*));
290  );
291  ($it:tt, $self:expr, $input:ident, $start:ident, $res:expr, $err:expr,) => ();
292);
293
294permutation_trait!(
295  P1 O1 o1
296  P2 O2 o2
297  P3 O3 o3
298  P4 O4 o4
299  P5 O5 o5
300  P6 O6 o6
301  P7 O7 o7
302  P8 O8 o8
303  P9 O9 o9
304  P10 O10 o10
305  P11 O11 o11
306  P12 O12 o12
307  P13 O13 o13
308  P14 O14 o14
309  P15 O15 o15
310  P16 O16 o16
311  P17 O17 o17
312  P18 O18 o18
313  P19 O19 o19
314  P20 O20 o20
315  P21 O21 o21
316);