Skip to main content

combine/parser/
choice.rs

1//! Combinators which take one or more parsers and attempts to parse successfully with at least one
2//! of them.
3
4use crate::{
5    error::{
6        ParseError,
7        ParseResult::{self, *},
8        ResultExt, StreamError, Tracked,
9    },
10    parser::ParseMode,
11    ErrorOffset, Parser, Stream, StreamOnce,
12};
13
14/// Takes a number of parsers and tries to apply them each in order.
15/// Fails if all the parsers fails or if an applied parser fails after it has committed to its
16/// parse.
17///
18/// ```
19/// # #[macro_use]
20/// # extern crate combine;
21/// # use combine::*;
22/// # use combine::parser::char::{digit, letter, string};
23/// # use combine::stream::easy::Error;
24/// # fn main() {
25/// let mut parser = choice!(
26///     many1(digit()),
27///     string("let").map(|s| s.to_string()),
28///     many1(letter()));
29/// assert_eq!(parser.parse("let"), Ok(("let".to_string(), "")));
30/// assert_eq!(parser.parse("123abc"), Ok(("123".to_string(), "abc")));
31/// assert!(parser.parse(":123").is_err());
32/// # }
33/// ```
34#[macro_export]
35macro_rules! choice {
36    ($first : expr) => {
37        $first
38    };
39    ($first : expr, $($rest : expr),+) => {
40        $first.or(choice!($($rest),+))
41    }
42}
43
44#[macro_export]
45#[doc(hidden)]
46macro_rules! parse_mode_choice {
47    (Input) => {
48        fn parse_partial(
49            &mut self,
50            input: &mut Input,
51            state: &mut Self::PartialState,
52        ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
53            self.parse_mode_choice($crate::parser::PartialMode::default(), input, state)
54        }
55
56        fn parse_first(
57            &mut self,
58            input: &mut Input,
59            state: &mut Self::PartialState,
60        ) -> ParseResult<Self::Output, Input::Error> {
61            self.parse_mode_choice($crate::parser::FirstMode, input, state)
62        }
63    };
64}
65
66/// `ChoiceParser` represents a parser which may parse one of several different choices depending
67/// on the input.
68///
69/// This is an internal trait used to overload the `choice` function.
70pub trait ChoiceParser<Input: Stream> {
71    type Output;
72    type PartialState: Default;
73
74    fn parse_first(
75        &mut self,
76        input: &mut Input,
77        state: &mut Self::PartialState,
78    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>;
79
80    fn parse_partial(
81        &mut self,
82        input: &mut Input,
83        state: &mut Self::PartialState,
84    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>;
85
86    fn parse_mode_choice<M>(
87        &mut self,
88        mode: M,
89        input: &mut Input,
90        state: &mut Self::PartialState,
91    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
92    where
93        M: ParseMode,
94        Self: Sized;
95
96    fn add_error_choice(&mut self, error: &mut Tracked<<Input as StreamOnce>::Error>);
97}
98
99impl<'a, Input, P> ChoiceParser<Input> for &'a mut P
100where
101    Input: Stream,
102    P: ?Sized + ChoiceParser<Input>,
103{
104    type Output = P::Output;
105    type PartialState = P::PartialState;
106
107    parse_mode_choice!(Input);
108    #[inline]
109    fn parse_mode_choice<M>(
110        &mut self,
111        mode: M,
112        input: &mut Input,
113        state: &mut Self::PartialState,
114    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
115    where
116        M: ParseMode,
117    {
118        if mode.is_first() {
119            (**self).parse_first(input, state)
120        } else {
121            (**self).parse_partial(input, state)
122        }
123    }
124
125    fn add_error_choice(&mut self, error: &mut Tracked<<Input as StreamOnce>::Error>) {
126        (**self).add_error_choice(error)
127    }
128}
129
130macro_rules! merge {
131    ($head: ident) => {
132        $head.error
133    };
134    ($head: ident $($tail: ident)+) => {
135        $head.error.merge(merge!($($tail)+))
136    };
137}
138
139macro_rules! do_choice {
140    (
141        $input: ident
142        $before_position: ident
143        $before: ident
144        $partial_state: ident
145        $state: ident
146        ( )
147        $($parser: ident $error: ident)+
148    ) => { {
149        let mut error = Tracked::from(merge!($($error)+));
150        // If offset != 1 then the nested parser is a sequence of parsers where 1 or
151        // more parsers returned `PeekOk` before the parser finally failed with
152        // `PeekErr`. Since we lose the offsets of the nested parsers when we merge
153        // the errors we must first extract the errors before we do the merge.
154        // If the offset == 0 on the other hand (which should be the common case) then
155        // we can delay the addition of the error since we know for certain that only
156        // the first parser in the sequence were tried
157        $(
158            if $error.offset != ErrorOffset(1) {
159                error.offset = $error.offset;
160                $parser.add_error(&mut error);
161                error.offset = ErrorOffset(0);
162            }
163        )+
164        PeekErr(error)
165    } };
166    (
167        $input: ident
168        $before_position: ident
169        $before: ident
170        $partial_state: ident
171        $state: ident
172        ( $head: ident $($tail: ident)* )
173        $($all: ident)*
174    ) => { {
175        let parser = $head;
176        let mut state = $head::PartialState::default();
177        match parser.parse_mode(crate::parser::FirstMode, $input, &mut state) {
178            CommitOk(x) => CommitOk(x),
179            PeekOk(x) => PeekOk(x),
180            CommitErr(err) => {
181                // If we get `CommitErr` but the input is the same this is a partial parse we
182                // cannot commit to so leave the state as `Peek` to retry all the parsers
183                // on the next call to  `parse_partial`
184                if $input.position() != $before_position {
185                    *$state = self::$partial_state::$head(state);
186                }
187                CommitErr(err)
188            }
189            PeekErr($head) => {
190                ctry!($input.reset($before.clone()).committed());
191                do_choice!(
192                    $input
193                    $before_position
194                    $before
195                    $partial_state
196                    $state
197                    ( $($tail)* )
198                    $($all)*
199                    parser
200                    $head
201                )
202            }
203        }
204    } }
205}
206
207macro_rules! tuple_choice_parser {
208    ($head: ident) => {
209        tuple_choice_parser_inner!($head; $head);
210    };
211    ($head: ident $($id: ident)+) => {
212        tuple_choice_parser_inner!($head; $head $($id)+);
213        tuple_choice_parser!($($id)+);
214    };
215}
216
217macro_rules! tuple_choice_parser_inner {
218    ($partial_state: ident; $($id: ident)+) => {
219        #[doc(hidden)]
220        pub enum $partial_state<$($id),+> {
221            Peek,
222            $(
223                $id($id),
224            )+
225        }
226
227        impl<$($id),+> Default for self::$partial_state<$($id),+> {
228            fn default() -> Self {
229                self::$partial_state::Peek
230            }
231        }
232
233        #[allow(non_snake_case)]
234        impl<Input, Output $(,$id)+> ChoiceParser<Input> for ($($id,)+)
235        where
236            Input: Stream,
237            $($id: Parser< Input, Output = Output>),+
238        {
239
240            type Output = Output;
241            type PartialState = self::$partial_state<$($id::PartialState),+>;
242
243            parse_mode_choice!(Input);
244            #[inline]
245            fn parse_mode_choice<Mode>(
246                &mut self,
247                mode: Mode,
248                input: &mut Input,
249                state: &mut Self::PartialState,
250            ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
251            where
252                Mode: ParseMode,
253            {
254                let ($(ref mut $id,)+) = *self;
255                let empty = match *state {
256                    self::$partial_state::Peek => true,
257                    _ => false,
258                };
259                if mode.is_first() || empty {
260                    let before_position = input.position();
261                    let before = input.checkpoint();
262                    do_choice!(input before_position before $partial_state state ( $($id)+ ) )
263                } else {
264                    match *state {
265                        self::$partial_state::Peek => unreachable!(),
266                        $(
267                            self::$partial_state::$id(_) => {
268                                let result = match *state {
269                                    self::$partial_state::$id(ref mut state) => {
270                                        $id.parse_mode(mode, input, state)
271                                    }
272                                    _ => unreachable!()
273                                };
274                                if result.is_ok() {
275                                    *state = self::$partial_state::Peek;
276                                }
277                                result
278                            }
279                        )+
280                    }
281                }
282            }
283
284            fn add_error_choice(
285                &mut self,
286                error: &mut Tracked<<Input as StreamOnce>::Error>
287            ) {
288                if error.offset != ErrorOffset(0) {
289                    let ($(ref mut $id,)+) = *self;
290                    // Reset the offset to 1 on every add so that we always (and only) takes the
291                    // error of the first parser. If we don't do this the first parser will consume
292                    // the offset to the detriment for all the other parsers.
293                    $(
294                        error.offset = ErrorOffset(1);
295                        $id.add_error(error);
296                    )+
297                }
298            }
299        }
300    }
301}
302
303tuple_choice_parser!(A B C D E F G H I J K L M N O P Q R S T U V X Y Z);
304
305macro_rules! array_choice_parser {
306    ($($t: tt)+) => {
307        $(
308        impl<Input, P> ChoiceParser<Input> for [P; $t]
309        where
310            Input: Stream,
311            P: Parser<Input>,
312        {
313
314            type Output = P::Output;
315            type PartialState = <[P] as ChoiceParser<Input>>::PartialState;
316
317            parse_mode_choice!(Input);
318            #[inline]
319            fn parse_mode_choice<M>(
320                &mut self,
321                mode: M,
322                input: &mut Input,
323                state: &mut Self::PartialState,
324            ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
325            where
326                M: ParseMode,
327            {
328                if mode.is_first() {
329                    self[..].parse_first(input, state)
330                } else {
331                    self[..].parse_partial(input, state)
332                }
333            }
334            fn add_error_choice(
335                &mut self,
336                error: &mut Tracked<<Input as StreamOnce>::Error>
337            ) {
338                self[..].add_error_choice(error)
339            }
340        }
341        )+
342    };
343}
344
345#[rustfmt::skip]
346array_choice_parser!(
347    0 1 2 3 4 5 6 7 8 9
348    10 11 12 13 14 15 16 17 18 19
349    20 21 22 23 24 25 26 27 28 29
350    30 31 32
351);
352
353#[derive(Copy, Clone)]
354pub struct Choice<P>(P);
355
356impl<Input, P> Parser<Input> for Choice<P>
357where
358    Input: Stream,
359    P: ChoiceParser<Input>,
360{
361    type Output = P::Output;
362    type PartialState = P::PartialState;
363
364    parse_mode!(Input);
365    #[inline]
366    fn parse_mode_impl<M>(
367        &mut self,
368        mode: M,
369        input: &mut Input,
370        state: &mut Self::PartialState,
371    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
372    where
373        M: ParseMode,
374    {
375        self.0.parse_mode_choice(mode, input, state)
376    }
377
378    fn add_error(&mut self, error: &mut Tracked<<Input as StreamOnce>::Error>) {
379        let before = error.offset.0;
380        self.0.add_error_choice(error);
381        error.offset.0 = before.saturating_sub(1);
382    }
383}
384
385fn slice_parse_mode<Input, P, M>(
386    self_: &mut [P],
387    mode: M,
388    input: &mut Input,
389    state: &mut (usize, P::PartialState),
390) -> ParseResult<P::Output, <Input as StreamOnce>::Error>
391where
392    P: Parser<Input>,
393    Input: Stream,
394    M: ParseMode,
395{
396    let mut prev_err = None;
397    let mut last_parser_having_non_1_offset = 0;
398    let before = input.checkpoint();
399
400    let (ref mut index_state, ref mut child_state) = *state;
401    if !mode.is_first() && *index_state != 0 {
402        return self_[*index_state - 1]
403            .parse_partial(input, child_state)
404            .map(|x| {
405                *index_state = 0;
406                x
407            });
408    }
409
410    for i in 0..self_.len() {
411        ctry!(input.reset(before.clone()).committed());
412
413        match self_[i].parse_mode(mode, input, child_state) {
414            committed_err @ CommitErr(_) => {
415                *index_state = i + 1;
416                return committed_err;
417            }
418            PeekErr(err) => {
419                prev_err = match prev_err {
420                    None => Some(err),
421                    Some(mut prev_err) => {
422                        if prev_err.offset != ErrorOffset(1) {
423                            // First add the errors of all the preceding parsers which did not
424                            // have a sequence of parsers returning `PeekOk` before failing
425                            // with `PeekErr`.
426                            let offset = prev_err.offset;
427                            for p in &mut self_[last_parser_having_non_1_offset..(i - 1)] {
428                                prev_err.offset = ErrorOffset(1);
429                                p.add_error(&mut prev_err);
430                            }
431                            // Then add the errors if the current parser
432                            prev_err.offset = offset;
433                            self_[i - 1].add_error(&mut prev_err);
434                            last_parser_having_non_1_offset = i;
435                        }
436                        Some(Tracked {
437                            error: prev_err.error.merge(err.error),
438                            offset: err.offset,
439                        })
440                    }
441                };
442            }
443            ok @ CommitOk(_) | ok @ PeekOk(_) => {
444                *index_state = 0;
445                return ok;
446            }
447        }
448    }
449    PeekErr(match prev_err {
450        None => Input::Error::from_error(
451            input.position(),
452            StreamError::message_static_message("parser choice is empty"),
453        )
454        .into(),
455        Some(mut prev_err) => {
456            if prev_err.offset != ErrorOffset(1) {
457                let offset = prev_err.offset;
458                let len = self_.len();
459                for p in &mut self_[last_parser_having_non_1_offset..(len - 1)] {
460                    prev_err.offset = ErrorOffset(1);
461                    p.add_error(&mut prev_err);
462                }
463                prev_err.offset = offset;
464                self_.last_mut().unwrap().add_error(&mut prev_err);
465                prev_err.offset = ErrorOffset(0);
466            }
467            prev_err
468        }
469    })
470}
471
472impl<Input, O, P> ChoiceParser<Input> for [P]
473where
474    Input: Stream,
475    P: Parser<Input, Output = O>,
476{
477    type Output = O;
478    type PartialState = (usize, P::PartialState);
479
480    #[inline]
481    fn parse_partial(
482        &mut self,
483        input: &mut Input,
484        state: &mut Self::PartialState,
485    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
486        slice_parse_mode(self, crate::parser::PartialMode::default(), input, state)
487    }
488
489    #[inline]
490    fn parse_first(
491        &mut self,
492        input: &mut Input,
493        state: &mut Self::PartialState,
494    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
495        slice_parse_mode(self, crate::parser::FirstMode, input, state)
496    }
497
498    #[allow(dead_code)] // this needs to be there for rust 1.85
499    #[inline]
500    fn parse_mode_choice<M>(
501        &mut self,
502        _mode: M,
503        _input: &mut Input,
504        _state: &mut Self::PartialState,
505    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
506    where
507        M: ParseMode,
508    {
509        unreachable!()
510    }
511
512    fn add_error_choice(&mut self, error: &mut Tracked<<Input as StreamOnce>::Error>) {
513        if error.offset != ErrorOffset(0) {
514            for p in self {
515                error.offset = ErrorOffset(1);
516                p.add_error(error);
517            }
518        }
519    }
520}
521
522/// Takes a tuple, a slice or an array of parsers and tries to apply them each in order.
523/// Fails if all the parsers fails or if an applied parser consumes input before failing.
524///
525/// ```
526/// # extern crate combine;
527/// # use combine::*;
528/// # use combine::parser::char::{digit, string};
529/// # fn main() {
530/// // `choice` is overloaded on tuples so that different types of parsers can be used
531/// // (each parser must still have the same input and output types)
532/// let mut parser = choice((
533///     string("Apple").map(|s| s.to_string()),
534///     many1(digit()),
535///     string("Orange").map(|s| s.to_string()),
536/// ));
537/// assert_eq!(parser.parse("1234"), Ok(("1234".to_string(), "")));
538/// assert_eq!(parser.parse("Orangexx"), Ok(("Orange".to_string(), "xx")));
539/// assert!(parser.parse("Appl").is_err());
540/// assert!(parser.parse("Pear").is_err());
541///
542/// // If arrays or slices are used then all parsers must have the same type
543/// // (`string` in this case)
544/// let mut parser2 = choice([string("one"), string("two"), string("three")]);
545/// // Fails as the parser for "two" consumes the first 't' before failing
546/// assert!(parser2.parse("three").is_err());
547///
548/// // Use 'attempt' to make failing parsers always act as if they have not committed any input
549/// let mut parser3 = choice([attempt(string("one")), attempt(string("two")), attempt(string("three"))]);
550/// assert_eq!(parser3.parse("three"), Ok(("three", "")));
551/// # }
552/// ```
553pub fn choice<Input, P>(ps: P) -> Choice<P>
554where
555    Input: Stream,
556    P: ChoiceParser<Input>,
557{
558    Choice(ps)
559}
560
561#[derive(Copy, Clone)]
562pub struct Or<P1, P2>(Choice<(P1, P2)>);
563impl<Input, O, P1, P2> Parser<Input> for Or<P1, P2>
564where
565    Input: Stream,
566    P1: Parser<Input, Output = O>,
567    P2: Parser<Input, Output = O>,
568{
569    type Output = O;
570    type PartialState = <Choice<(P1, P2)> as Parser<Input>>::PartialState;
571
572    parse_mode!(Input);
573    #[inline]
574    fn parse_mode_impl<M>(
575        &mut self,
576        mode: M,
577        input: &mut Input,
578        state: &mut Self::PartialState,
579    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
580    where
581        M: ParseMode,
582    {
583        self.0.parse_mode(mode, input, state)
584    }
585
586    #[inline]
587    fn add_error(&mut self, errors: &mut Tracked<<Input as StreamOnce>::Error>) {
588        if errors.offset != ErrorOffset(0) {
589            self.0.add_error(errors);
590        }
591    }
592}
593
594/// Equivalent to [`p1.or(p2)`].
595///
596/// If you are looking to chain 3 or more parsers using `or` you may consider using the
597/// [`choice!`] macro instead, which can be clearer and may result in a faster parser.
598///
599/// ```
600/// # extern crate combine;
601/// # use combine::*;
602/// # use combine::parser::choice::or;
603/// # use combine::parser::char::{digit, string};
604/// # fn main() {
605/// let mut parser = or(
606///     string("let"),
607///     or(digit().map(|_| "digit"), string("led")),
608/// );
609/// assert_eq!(parser.parse("let"), Ok(("let", "")));
610/// assert_eq!(parser.parse("1"), Ok(("digit", "")));
611/// assert!(parser.parse("led").is_err());
612///
613/// let mut parser2 = or(string("two"), string("three"));
614/// // Fails as the parser for "two" consumes the first 't' before failing
615/// assert!(parser2.parse("three").is_err());
616///
617/// // Use 'attempt' to make failing parsers always act as if they have not committed any input
618/// let mut parser3 = or(attempt(string("two")), attempt(string("three")));
619/// assert_eq!(parser3.parse("three"), Ok(("three", "")));
620/// # }
621/// ```
622///
623/// [`choice!`]: ../../macro.choice.html
624/// [`p1.or(p2)`]: ../trait.Parser.html#method.or
625pub fn or<Input, P1, P2>(p1: P1, p2: P2) -> Or<P1, P2>
626where
627    Input: Stream,
628    P1: Parser<Input>,
629    P2: Parser<Input, Output = P1::Output>,
630{
631    Or(choice((p1, p2)))
632}
633
634#[derive(Copy, Clone)]
635pub struct Optional<P>(P);
636impl<Input, P> Parser<Input> for Optional<P>
637where
638    Input: Stream,
639    P: Parser<Input>,
640{
641    type Output = Option<P::Output>;
642    type PartialState = P::PartialState;
643
644    parse_mode!(Input);
645    #[inline]
646    fn parse_mode_impl<M>(
647        &mut self,
648        mode: M,
649        input: &mut Input,
650        state: &mut Self::PartialState,
651    ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
652    where
653        M: ParseMode,
654    {
655        let before = input.checkpoint();
656        match self.0.parse_mode(mode, input, state) {
657            PeekOk(x) => PeekOk(Some(x)),
658            CommitOk(x) => CommitOk(Some(x)),
659            CommitErr(err) => CommitErr(err),
660            PeekErr(_) => {
661                ctry!(input.reset(before).committed());
662                PeekOk(None)
663            }
664        }
665    }
666
667    forward_parser!(Input, add_error parser_count, 0);
668}
669
670/// Parses `parser` and outputs `Some(value)` if it succeeds, `None` if it fails without
671/// consuming any input. Fails if `parser` fails after having committed some input.
672///
673/// ```
674/// # extern crate combine;
675/// # use combine::*;
676/// # use combine::parser::char::string;
677/// # fn main() {
678/// let mut parser = optional(string("hello"));
679/// assert_eq!(parser.parse("hello"), Ok((Some("hello"), "")));
680/// assert_eq!(parser.parse("world"), Ok((None, "world")));
681/// assert!(parser.parse("heya").is_err());
682/// # }
683/// ```
684pub fn optional<Input, P>(parser: P) -> Optional<P>
685where
686    Input: Stream,
687    P: Parser<Input>,
688{
689    Optional(parser)
690}
691
692#[macro_export]
693#[doc(hidden)]
694macro_rules! parse_mode_dispatch {
695    () => {
696        fn parse_partial(
697            &mut self,
698            input: &mut Input,
699            state: &mut Self::PartialState,
700        ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
701            self.parse_mode_dispatch($crate::parser::PartialMode::default(), input, state)
702        }
703
704        fn parse_first(
705            &mut self,
706            input: &mut Input,
707            state: &mut Self::PartialState,
708        ) -> ParseResult<Self::Output, <Input as StreamOnce>::Error> {
709            self.parse_mode_dispatch($crate::parser::FirstMode, input, state)
710        }
711    };
712}
713
714#[macro_export]
715#[doc(hidden)]
716macro_rules! dispatch_parser_impl {
717    ($parser_name: ident [$first_ident: ident $($id: ident)*] [$($collected_idents: ident)*] $expr: expr, $($rest: expr,)*) => {
718        $crate::dispatch_parser_impl!{ $parser_name [ $($id)* ] [$($collected_idents)* $first_ident] $($rest,)*}
719    };
720    ($parser_name: ident [$($id: ident)*] [$($collected_idents: ident)*]) => {
721        $crate::dispatch_parser_impl!{ $parser_name; $($collected_idents)* }
722    };
723
724    ($parser_name: ident; $($id: ident)*) => {
725        pub enum $parser_name<$($id),*> {
726            $(
727                $id($id),
728            )*
729        }
730
731        #[allow(non_snake_case)]
732        impl<Input, Output, $($id),*> $crate::Parser<Input> for $parser_name<$($id),*>
733            where
734                $( $id: $crate::Parser<Input, Output = Output>, )*
735                Input: $crate::Stream,
736        {
737            type Output = Output;
738            type PartialState = Option<$parser_name<$($id::PartialState),*>>;
739
740            $crate::parse_mode!(Input);
741            fn parse_mode<Mode>(
742                &mut self,
743                mode: Mode,
744                input: &mut Input,
745                state: &mut Self::PartialState,
746            ) -> $crate::error::ParseResult<Self::Output, <Input as $crate::StreamOnce>::Error>
747            where
748                Mode: $crate::parser::ParseMode,
749            {
750                match self {
751                    $(
752                    $parser_name::$id($id) => {
753                        let state = match state {
754                            Some($parser_name::$id(s)) => s,
755                            _ => {
756                                *state = Some($parser_name::$id(Default::default()));
757                                match state {
758                                    Some($parser_name::$id(s)) => s,
759                                    _ => unreachable!(),
760                                }
761                            }
762                        };
763                        $id.parse_mode(mode, input, state)
764                    }
765                    )*
766                }
767            }
768
769            fn add_error(&mut self, error: &mut $crate::error::Tracked<<Input as $crate::StreamOnce>::Error>) {
770                match self {
771                    $(
772                    $parser_name::$id($id) => $id.add_error(error),
773                    )*
774                }
775            }
776        }
777    }
778}
779
780#[macro_export]
781#[doc(hidden)]
782macro_rules! dispatch_inner {
783    ($expr_ident: ident [$first_ident: ident $($id: ident)*] [$($collected: tt)*] $($pat: pat)|+ $(if $pred:expr)? => $expr: expr, $($rest_alt: tt)*) => {
784        $crate::dispatch_inner!{ $expr_ident [ $($id)* ] [$($collected)* $first_ident $($pat)|+ $(if $pred)? => $expr,] $($rest_alt)*}
785    };
786    ($expr_ident: ident [$($id: ident)*] [$($collected: tt)*]) => {
787        $crate::dispatch_inner!{ $expr_ident $($collected)* }
788    };
789    ($expr_ident: ident [$($ident_tt: tt)*]) => {
790        unreachable!()
791    };
792    ($expr_ident: ident $( $ident: ident $($pat: pat)|+ $(if $pred:expr)? => $expr: expr,)+ ) => {
793        match $expr_ident {
794            $(
795                $($pat)|+ $(if $pred)? => Dispatch::$ident(check_parser($expr)),
796            )+
797        }
798    }
799}
800
801/// `dispatch!` allows a parser to be constructed depending on earlier input, without forcing each
802/// branch to have the same type of parser
803///
804/// ```
805/// use combine::{dispatch, any, token, satisfy, EasyParser, Parser};
806///
807/// let mut parser = any().then(|e| {
808///     dispatch!(e;
809///         'a' => token('a'),
810///         'b' => satisfy(|b| b == 'b'),
811///         t if t == 'c' => any(),
812///         _ => token('d')
813///     )
814/// });
815/// assert_eq!(parser.easy_parse("aa"), Ok(('a', "")));
816/// assert_eq!(parser.easy_parse("cc"), Ok(('c', "")));
817/// assert_eq!(parser.easy_parse("cd"), Ok(('d', "")));
818/// assert!(parser.easy_parse("ab").is_err());
819/// ```
820#[macro_export]
821macro_rules! dispatch {
822    ($match_expr: expr; $( $($pat: pat)|+ $(if $pred:expr)? => $expr: expr ),+ $(,)? ) => {
823        {
824            $crate::dispatch_parser_impl!{ Dispatch [A B C D E F G H I J K L M N O P Q R S T U V X Y Z] [] $($expr,)+ }
825
826            fn check_parser<Input, P>(p: P) -> P where P: $crate::Parser<Input>, Input: $crate::Stream { p }
827
828            let e = $match_expr;
829            let parser = $crate::dispatch_inner!(e [A B C D E F G H I J K L M N O P Q R S T U V X Y Z] []
830                $(
831                    $($pat)|+ $(if $pred)? => $expr,
832                )*
833            );
834            parser
835        }
836    }
837}
838
839#[cfg(all(feature = "std", test))]
840mod tests {
841
842    use crate::parser::{token::any, EasyParser};
843
844    use super::*;
845
846    #[test]
847    fn choice_single_parser() {
848        assert!(choice((any(),),).easy_parse("a").is_ok());
849    }
850}