logical_expressions/
parser.rs

1use std::str::FromStr;
2
3use thiserror::Error;
4
5use super::LogicalExpression;
6
7/// Represents the possible errors that can occur during parsing of a logical expression.
8#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)]
9pub enum ParseError<E> {
10    /// Represents an error that occurred while parsing a condition.
11    #[error("Error parsing condition: {0}")]
12    ConditionParsing(E),
13
14    /// Represents an error when there is no matching opening bracket for a closing bracket.
15    #[error("No matching opening bracket")]
16    NoMatchingOpeningBracket,
17
18    /// Represents an error when there is no matching closing bracket for an opening bracket.
19    #[error("No matching closing bracket")]
20    NoMatchingClosingBracket,
21
22    /// Represents an error when there are multiple operators without a condition between them.
23    #[error("Multiple operators without a condition between them")]
24    MultipleOperators,
25
26    /// Represents an error when there is an empty condition.
27    #[error("Empty condition")]
28    EmptyCondition,
29
30    /// Represents an error when there is a leading operator without a preceding condition.
31    #[error("Leading operator without a preceding condition")]
32    LeadingOperator,
33
34    /// Represents an error when therec is a trailing operator without a following condition.
35    #[error("Trailing operator without a following condition")]
36    TrailingOperator,
37
38    /// Represents an error when there is a condition before an opening bracket.
39    #[error("Condition before an opening bracket")]
40    ConditionBeforeOpeningBracket,
41
42    /// Represents an error when there is a condition after a closing bracket.
43    #[error("Condition after a closing bracket")]
44    ConditionAfterClosingBracket,
45}
46
47impl<E> From<E> for ParseError<E> {
48    fn from(err: E) -> Self {
49        Self::ConditionParsing(err)
50    }
51}
52
53struct Lists<T> {
54    or: Vec<T>,
55    and: Vec<T>,
56}
57
58impl<T> Lists<T> {
59    fn new() -> Self {
60        Self {
61            or: Vec::new(),
62            and: Vec::new(),
63        }
64    }
65}
66
67impl<C: FromStr> LogicalExpression<C> {
68    /// Parses a logical expression from a string.
69    ///
70    /// Returns a `Result` containing the parsed `LogicalExpression` if successful,
71    /// or a `ParseError` if an error occurred during parsing.
72    #[inline]
73    pub fn parse(s: &str) -> Result<Self, ParseError<<C as FromStr>::Err>> {
74        Self::parse_with(s, FromStr::from_str)
75    }
76}
77
78impl<C> LogicalExpression<C> {
79    /// Parses a logical expression from a string using a custom parsing function.
80    ///
81    /// The `parse_condition` function is used to parse individual conditions from string slices.
82    ///
83    /// Returns a `Result` containing the parsed `LogicalExpression` if successful,
84    /// or a `ParseError` if an error occurred during parsing.
85    pub fn parse_with<F, E>(s: &str, mut parse_condition: F) -> Result<Self, ParseError<E>>
86    where
87        F: FnMut(&str) -> Result<C, E>,
88    {
89        let mut bracket_stack = Vec::new();
90        let mut lists = Lists::new();
91        let mut start = 0;
92        let mut end = 0;
93
94        enum After {
95            Start,
96            Operator,
97        }
98
99        let mut state = Some(After::Start);
100
101        for c in s.chars() {
102            let clen = c.len_utf8();
103            match c {
104                '|' | '&' => {
105                    let condition = s[start..end].trim();
106                    if let Some(after) = state {
107                        if condition.is_empty() {
108                            return Err(match after {
109                                After::Start => ParseError::LeadingOperator,
110                                After::Operator => ParseError::MultipleOperators,
111                            });
112                        }
113                        lists.and.push(Self::Condition(parse_condition(condition)?));
114                    } else if !condition.is_empty() {
115                        return Err(ParseError::ConditionAfterClosingBracket);
116                    }
117
118                    start = end + clen;
119
120                    if c == '|' {
121                        lists.or.push(Self::and(lists.and));
122                        lists.and = Vec::new();
123                    }
124
125                    state = Some(After::Operator);
126                }
127                '(' => {
128                    let condition = s[start..end].trim();
129                    if !condition.is_empty() {
130                        return Err(ParseError::ConditionBeforeOpeningBracket);
131                    }
132
133                    bracket_stack.push(lists);
134                    lists = Lists::new();
135
136                    start = end + clen;
137
138                    state = Some(After::Start);
139                }
140                ')' => {
141                    let Some(mut stack_lists) = bracket_stack.pop() else {
142                        return Err(ParseError::NoMatchingOpeningBracket);
143                    };
144
145                    let condition = s[start..end].trim();
146                    if let Some(after) = state {
147                        if condition.is_empty() {
148                            return Err(match after {
149                                After::Start => ParseError::EmptyCondition,
150                                After::Operator => ParseError::TrailingOperator,
151                            });
152                        }
153                        lists.and.push(Self::Condition(parse_condition(condition)?));
154                    } else if !condition.is_empty() {
155                        return Err(ParseError::ConditionAfterClosingBracket);
156                    }
157
158                    start = end + clen;
159
160                    lists.or.push(Self::and(lists.and));
161
162                    stack_lists.and.push(Self::or(lists.or));
163
164                    lists = stack_lists;
165
166                    state = None;
167                }
168                _ => (),
169            }
170            end += clen;
171        }
172
173        if !bracket_stack.is_empty() {
174            return Err(ParseError::NoMatchingClosingBracket);
175        }
176
177        let condition = s[start..end].trim();
178        if let Some(after) = state {
179            if condition.is_empty() {
180                return Err(match after {
181                    After::Start => ParseError::EmptyCondition,
182                    After::Operator => ParseError::TrailingOperator,
183                });
184            }
185            lists.and.push(Self::Condition(parse_condition(condition)?));
186        } else if !condition.is_empty() {
187            return Err(ParseError::ConditionAfterClosingBracket);
188        }
189
190        lists.or.push(Self::and(lists.and));
191
192        Ok(Self::or(lists.or))
193    }
194}