1use crate::combinator::trace;
2use crate::error::ParserError;
3use crate::stream::Stream;
4use crate::{Parser, Result};
5
6pub trait Alt<I, O, E> {
10 fn choice(&mut self, input: &mut I) -> Result<O, E>;
12}
13
14#[doc(alias = "choice")]
48#[inline(always)]
49pub fn alt<Input: Stream, Output, Error, Alternatives>(
50 mut alternatives: Alternatives,
51) -> impl Parser<Input, Output, Error>
52where
53 Alternatives: Alt<Input, Output, Error>,
54 Error: ParserError<Input>,
55{
56 trace("alt", move |i: &mut Input| alternatives.choice(i))
57}
58
59impl<const N: usize, I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for [P; N] {
60 fn choice(&mut self, input: &mut I) -> Result<O, E> {
61 let mut error: Option<E> = None;
62
63 let start = input.checkpoint();
64 for branch in self {
65 input.reset(&start);
66 match branch.parse_next(input) {
67 Err(e) if e.is_backtrack() => {
68 error = match error {
69 Some(error) => Some(error.or(e)),
70 None => Some(e),
71 };
72 }
73 res => return res,
74 }
75 }
76
77 match error {
78 Some(e) => Err(e.append(input, &start)),
79 None => Err(ParserError::assert(
80 input,
81 "`alt` needs at least one parser",
82 )),
83 }
84 }
85}
86
87impl<I: Stream, O, E: ParserError<I>, P: Parser<I, O, E>> Alt<I, O, E> for &mut [P] {
88 fn choice(&mut self, input: &mut I) -> Result<O, E> {
89 let mut error: Option<E> = None;
90
91 let start = input.checkpoint();
92 for branch in self.iter_mut() {
93 input.reset(&start);
94 match branch.parse_next(input) {
95 Err(e) if e.is_backtrack() => {
96 error = match error {
97 Some(error) => Some(error.or(e)),
98 None => Some(e),
99 };
100 }
101 res => return res,
102 }
103 }
104
105 match error {
106 Some(e) => Err(e.append(input, &start)),
107 None => Err(ParserError::assert(
108 input,
109 "`alt` needs at least one parser",
110 )),
111 }
112 }
113}
114
115macro_rules! alt_trait(
116 ($first:ident $second:ident $($id: ident)+) => (
117 alt_trait!(__impl $first $second; $($id)+);
118 );
119 (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
120 alt_trait_impl!($($current)*);
121
122 alt_trait!(__impl $($current)* $head; $($id)+);
123 );
124 (__impl $($current:ident)*; $head:ident) => (
125 alt_trait_impl!($($current)*);
126 alt_trait_impl!($($current)* $head);
127 );
128);
129
130macro_rules! alt_trait_impl(
131 ($($id:ident)+) => (
132 impl<
133 I: Stream, Output, Error: ParserError<I>,
134 $($id: Parser<I, Output, Error>),+
135 > Alt<I, Output, Error> for ( $($id),+ ) {
136
137 fn choice(&mut self, input: &mut I) -> Result<Output, Error> {
138 let start = input.checkpoint();
139 match self.0.parse_next(input) {
140 Err(e) if e.is_backtrack() => alt_trait_inner!(1, self, input, start, e, $($id)+),
141 res => res,
142 }
143 }
144 }
145 );
146);
147
148macro_rules! succ (
149 (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
150 (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
151 (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
152 (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
153 (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
154 (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
155 (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
156 (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
157);
158
159macro_rules! alt_trait_inner(
160 ($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident $($id:ident)+) => ({
161 $input.reset(&$start);
162 match $self.$it.parse_next($input) {
163 Err(e) if e.is_backtrack() => {
164 let err = $err.or(e);
165 succ!($it, alt_trait_inner!($self, $input, $start, err, $($id)+))
166 }
167 res => res,
168 }
169 });
170 ($it:tt, $self:expr, $input:expr, $start:ident, $err:expr, $head:ident) => ({
171 Err($err.append($input, &$start))
172 });
173);
174
175alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10);
176
177impl<I: Stream, O, E: ParserError<I>, A: Parser<I, O, E>> Alt<I, O, E> for (A,) {
179 fn choice(&mut self, input: &mut I) -> Result<O, E> {
180 self.0.parse_next(input)
181 }
182}