1use crate::error_accumulator::ErrorAccumulator;
2use crate::{ParseDriver, Pos, Progress, Recoverable};
3
4#[must_use]
9#[derive(Debug)]
10pub struct Alternate<'pd, P: 'pd, T, E: 'pd, S, A: 'pd = ()> {
11 driver: &'pd mut ParseDriver<S>,
12 current: Option<Progress<P, T, E>>,
13 pos: P,
14 err_accumulator: A,
15}
16
17impl<'pd, P, T, E, S, A> Alternate<'pd, P, T, E, S, A>
18where
19 P: Pos,
20 E: Recoverable,
21 A: ErrorAccumulator<P, E>,
22{
23 fn run_one<F>(&mut self, parser: F)
24 where
25 F: FnOnce(&mut ParseDriver<S>, P) -> Progress<P, T, E>,
26 {
27 self.current = Some(parser(self.driver, self.pos))
28 }
29
30 #[inline]
32 pub fn new(driver: &'pd mut ParseDriver<S>, pos: P, err_accumulator: A) -> Self {
33 Self {
34 driver,
35 current: None,
36 pos,
37 err_accumulator,
38 }
39 }
40
41 #[inline]
43 pub fn one<F>(mut self, parser: F) -> Self
44 where
45 F: FnOnce(&mut ParseDriver<S>, P) -> Progress<P, T, E>,
46 {
47 match &mut self.current {
48 None => self.run_one(parser),
49 Some(Progress { status: Ok(..), .. }) => {
50 }
52 Some(Progress { status: Err(e), .. }) if e.recoverable() => {
53 let current = self.current.take().unwrap();
55
56 let _ = self.err_accumulator.add_progress(current);
58
59 self.run_one(parser)
60 }
61 Some(Progress {
62 status: Err(..), ..
63 }) => {
64 }
66 }
67
68 self
69 }
70
71 #[inline]
77 pub fn finish(self) -> Progress<P, T, A::Accumulated> {
78 let mut err_accumulator = self.err_accumulator;
79
80 let progress = err_accumulator.add_progress(self.current.unwrap());
82
83 progress.map_err(|_| err_accumulator.finish())
84 }
85}
86
87#[cfg(test)]
88mod test {
89 use crate::error_accumulator::AllErrorsAccumulator;
90 use crate::slice::BytePos;
91 use crate::{ParseDriver, Recoverable};
92
93 #[derive(Debug, PartialEq)]
94 pub struct TestError(bool);
95
96 impl Recoverable for TestError {
97 fn recoverable(&self) -> bool {
98 self.0
99 }
100 }
101
102 #[test]
103 fn it_returns_the_first_successful_branch() {
104 let input = &[0u8, 1, 2, 3, 4];
105 let pos = BytePos::new(input);
106 let pd = &mut ParseDriver::new();
107
108 let (res_pos, val) = pd
109 .alternate(pos)
110 .one(|_, pos| pos.failure(TestError(true)))
111 .one(|_, pos| pos.advance_by(1).success(0u8))
112 .one(|_, pos| pos.advance_by(2).success(1u8))
113 .finish()
114 .unwrap();
115
116 assert_eq!(res_pos.offset, 1usize);
117 assert_eq!(val, 0u8);
118 }
119
120 #[test]
121 fn it_stops_at_irrecoverable_errors() {
122 let input = &[0u8, 1, 2, 3, 4];
123 let pos = BytePos::new(input);
124 let pd = &mut ParseDriver::new();
125
126 let (res_pos, err) = pd
127 .alternate(pos)
128 .one(|_, pos| pos.failure(TestError(true)))
129 .one(|_, pos| pos.failure(TestError(false)))
130 .one(|_, pos| pos.advance_by(1).success(0u8))
131 .finish()
132 .unwrap_err();
133
134 assert_eq!(res_pos.offset, 0usize);
135 assert_eq!(err, TestError(false));
136 }
137
138 #[test]
139 fn it_accumulates_all_errors() {
140 let input = &[0u8, 1, 2, 3, 4];
141 let pos = BytePos::new(input);
142 let pd = &mut ParseDriver::new();
143
144 let (res_pos, err) = pd
145 .alternate_accumulate_errors(pos, AllErrorsAccumulator::new())
146 .one(|_, pos| pos.failure(TestError(true)))
147 .one(|_, pos| pos.failure(TestError(true)))
148 .one(|_, pos| pos.failure::<(), _>(TestError(false)))
149 .one(|_, pos| pos.failure(TestError(true)))
150 .finish()
151 .unwrap_err();
152
153 assert_eq!(res_pos.offset, 0usize);
154 assert_eq!(err, &[TestError(true), TestError(true), TestError(false)]);
156 }
157}