intuicio_parser/
alternation.rs

1use crate::{ParseResult, Parser, ParserExt, ParserHandle, ParserRegistry};
2use std::fmt::Write;
3
4pub mod shorthand {
5    use super::*;
6
7    pub fn alt(values: impl IntoIterator<Item = ParserHandle>) -> ParserHandle {
8        AlternationParser::from_iter(values).into_handle()
9    }
10}
11
12#[derive(Default, Clone)]
13pub struct AlternationParser {
14    parsers: Vec<ParserHandle>,
15}
16
17impl AlternationParser {
18    pub fn with(mut self, parser: ParserHandle) -> Self {
19        self.append(parser);
20        self
21    }
22
23    pub fn append(&mut self, parser: ParserHandle) {
24        self.parsers.push(parser);
25    }
26
27    pub fn prepend(&mut self, parser: ParserHandle) {
28        self.parsers.insert(0, parser);
29    }
30}
31
32impl Parser for AlternationParser {
33    fn parse<'a>(&self, registry: &ParserRegistry, input: &'a str) -> ParseResult<'a> {
34        let mut errors = String::new();
35        for parser in &self.parsers {
36            match parser.parse(registry, input) {
37                Ok(result) => {
38                    return Ok(result);
39                }
40                Err(error) => {
41                    if errors.is_empty() {
42                        write!(&mut errors, "{}", error)?;
43                    } else {
44                        write!(&mut errors, "\nOr: {}", error)?;
45                    }
46                }
47            }
48        }
49        Err(errors.into())
50    }
51}
52
53impl FromIterator<ParserHandle> for AlternationParser {
54    fn from_iter<T: IntoIterator<Item = ParserHandle>>(iter: T) -> Self {
55        Self {
56            parsers: iter.into_iter().collect(),
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use crate::{
64        alternation::AlternationParser,
65        shorthand::{alt, lit},
66        ParserRegistry,
67    };
68
69    fn is_async<T: Send + Sync>() {}
70
71    #[test]
72    fn test_alternation() {
73        is_async::<AlternationParser>();
74
75        let registry = ParserRegistry::default();
76        let sentence = alt([lit("foo"), lit("bar")]);
77        let (rest, result) = sentence.parse(&registry, "foo").unwrap();
78        assert_eq!(rest, "");
79        result.consume::<String>().ok().unwrap();
80        let (rest, result) = sentence.parse(&registry, "bar").unwrap();
81        assert_eq!(rest, "");
82        result.consume::<String>().ok().unwrap();
83        assert_eq!(
84            format!("{}", sentence.parse(&registry, "zee").err().unwrap()),
85            "Expected 'foo'\nOr: Expected 'bar'"
86        );
87    }
88}