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        Self::parse_with_expression(s, |s| Ok(Self::Condition(parse_condition(s)?)))
90    }
91
92    /// Parses a logical expression from a string using a custom parsing function.
93    ///
94    /// The `parse_expression` function is used to parse individual conditions from string slices into expressions.
95    ///
96    /// Returns a `Result` containing the parsed `LogicalExpression` if successful,
97    /// or a `ParseError` if an error occurred during parsing.
98    pub fn parse_with_expression<F, E>(
99        s: &str,
100        mut parse_expression: F,
101    ) -> Result<Self, ParseError<E>>
102    where
103        F: FnMut(&str) -> Result<Self, E>,
104    {
105        let mut bracket_stack = Vec::new();
106        let mut lists = Lists::new();
107        let mut start = 0;
108        let mut end = 0;
109
110        enum After {
111            Start,
112            Operator,
113        }
114
115        let mut state = Some(After::Start);
116
117        for c in s.chars() {
118            let clen = c.len_utf8();
119            match c {
120                '|' | '&' => {
121                    let condition = s[start..end].trim();
122                    if let Some(after) = state {
123                        if condition.is_empty() {
124                            return Err(match after {
125                                After::Start => ParseError::LeadingOperator,
126                                After::Operator => ParseError::MultipleOperators,
127                            });
128                        }
129                        lists.and.push(parse_expression(condition)?);
130                    } else if !condition.is_empty() {
131                        return Err(ParseError::ConditionAfterClosingBracket);
132                    }
133
134                    start = end + clen;
135
136                    if c == '|' {
137                        lists.or.push(Self::and(lists.and));
138                        lists.and = Vec::new();
139                    }
140
141                    state = Some(After::Operator);
142                }
143                '(' => {
144                    let condition = s[start..end].trim();
145                    if !condition.is_empty() {
146                        return Err(ParseError::ConditionBeforeOpeningBracket);
147                    }
148
149                    bracket_stack.push(lists);
150                    lists = Lists::new();
151
152                    start = end + clen;
153
154                    state = Some(After::Start);
155                }
156                ')' => {
157                    let Some(mut stack_lists) = bracket_stack.pop() else {
158                        return Err(ParseError::NoMatchingOpeningBracket);
159                    };
160
161                    let condition = s[start..end].trim();
162                    if let Some(after) = state {
163                        if condition.is_empty() {
164                            return Err(match after {
165                                After::Start => ParseError::EmptyCondition,
166                                After::Operator => ParseError::TrailingOperator,
167                            });
168                        }
169                        lists.and.push(parse_expression(condition)?);
170                    } else if !condition.is_empty() {
171                        return Err(ParseError::ConditionAfterClosingBracket);
172                    }
173
174                    start = end + clen;
175
176                    lists.or.push(Self::and(lists.and));
177
178                    stack_lists.and.push(Self::or(lists.or));
179
180                    lists = stack_lists;
181
182                    state = None;
183                }
184                _ => (),
185            }
186            end += clen;
187        }
188
189        if !bracket_stack.is_empty() {
190            return Err(ParseError::NoMatchingClosingBracket);
191        }
192
193        let condition = s[start..end].trim();
194        if let Some(after) = state {
195            if condition.is_empty() {
196                return Err(match after {
197                    After::Start => ParseError::EmptyCondition,
198                    After::Operator => ParseError::TrailingOperator,
199                });
200            }
201            lists.and.push(parse_expression(condition)?);
202        } else if !condition.is_empty() {
203            return Err(ParseError::ConditionAfterClosingBracket);
204        }
205
206        lists.or.push(Self::and(lists.and));
207
208        Ok(Self::or(lists.or))
209    }
210}