haar_lib/parser/
parse_paren.rs1use std::iter::Peekable;
4
5#[derive(Clone, Debug)]
7pub struct ParseResult<T> {
8 pub elems: Vec<Elem<T>>,
10}
11
12#[derive(Clone, Debug)]
14pub enum Elem<T> {
15 Value(T),
17 Paren {
19 open: T,
21 inner: ParseResult<T>,
23 close: T,
25 },
26}
27
28fn _parse<T: Copy + Eq + std::fmt::Debug>(
29 s: &mut Peekable<impl Iterator<Item = T>>,
30 open: T,
31 close: T,
32) -> Option<ParseResult<T>> {
33 let mut elems = vec![];
34
35 loop {
36 let c = s.peek();
37
38 match c {
39 None => break,
40 Some(&c) => {
41 if c == open {
42 s.next();
43 let inner = _parse(s, open, close)?;
44
45 let c = s.peek()?;
46 assert_eq!(c, &close);
47 elems.push(Elem::Paren { open, inner, close });
48 s.next();
49 } else if c == close {
50 break;
51 } else {
52 elems.push(Elem::Value(c));
53 s.next();
54 }
55 }
56 }
57 }
58
59 Some(ParseResult { elems })
60}
61
62pub fn parse_paren<T: Copy + Eq + std::fmt::Debug>(
64 s: impl IntoIterator<Item = T>,
65 open: T,
66 close: T,
67) -> Option<ParseResult<T>> {
68 assert_ne!(open, close);
69
70 let mut s = s.into_iter().peekable();
71 let res = _parse(&mut s, open, close);
72
73 if s.peek().is_none() {
74 res
75 } else {
76 None
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 fn check(s: &str) -> bool {
85 let a = parse_paren(s.chars(), '(', ')');
86 a.is_some()
87 }
88
89 #[test]
90 fn test() {
91 assert!(check("()"));
92 assert!(check("()()()"));
93 assert!(check("(()(()))"));
94
95 assert!(!check(")("));
96 assert!(!check("(()"));
97 assert!(!check("())"));
98 assert!(!check("(()()"));
99
100 assert!(check("a(bc(d)()e((f)g)h)i"));
101
102 assert!(!check("(()()aaa"));
103 }
104}