intuicio_parser/
alternation.rs1use 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(®istry, "foo").unwrap();
78 assert_eq!(rest, "");
79 result.consume::<String>().ok().unwrap();
80 let (rest, result) = sentence.parse(®istry, "bar").unwrap();
81 assert_eq!(rest, "");
82 result.consume::<String>().ok().unwrap();
83 assert_eq!(
84 format!("{}", sentence.parse(®istry, "zee").err().unwrap()),
85 "Expected 'foo'\nOr: Expected 'bar'"
86 );
87 }
88}