1use std::fmt;
25
26use super::{BinaryOp, Expression, NumberLiteral};
27use crate::common::ColumnName;
28
29pub const MAX_DEPTH: usize = 64;
33
34#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
36#[error("at position {position}: {kind}")]
37pub struct ExpressionError {
38 pub position: usize,
40 pub kind: ExpressionErrorKind,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
46pub enum ExpressionErrorKind {
47 #[error("the expression is empty")]
48 Empty,
49 #[error(
50 "unexpected character `{0}`: an expression holds column names, numbers, \
51 `+ - * /` and parentheses"
52 )]
53 UnexpectedCharacter(char),
54 #[error("a number needs a digit after its `.`")]
55 IncompleteNumber,
56 #[error("`{0}` is not a valid column name: at most 63 characters")]
57 InvalidColumn(String),
58 #[error("expected a column, a number, `-` or `(`, found {0}")]
59 ExpectedOperand(String),
60 #[error("expected an operator (`+ - * /`) or the end, found {0}")]
61 ExpectedOperator(String),
62 #[error("this `(` is never closed")]
63 UnclosedParenthesis,
64 #[error("this `)` has no matching `(`")]
65 UnmatchedParenthesis,
66 #[error("the expression nests deeper than {MAX_DEPTH} levels")]
67 TooDeep,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
71enum Token {
72 Column(String),
73 Number(String),
74 Plus,
75 Minus,
76 Star,
77 Slash,
78 Open,
79 Close,
80 End,
81}
82
83impl fmt::Display for Token {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 Self::Column(name) => write!(f, "column `{name}`"),
87 Self::Number(text) => write!(f, "number `{text}`"),
88 Self::Plus => f.write_str("`+`"),
89 Self::Minus => f.write_str("`-`"),
90 Self::Star => f.write_str("`*`"),
91 Self::Slash => f.write_str("`/`"),
92 Self::Open => f.write_str("`(`"),
93 Self::Close => f.write_str("`)`"),
94 Self::End => f.write_str("the end"),
95 }
96 }
97}
98
99fn error(position: usize, kind: ExpressionErrorKind) -> ExpressionError {
100 ExpressionError { position, kind }
101}
102
103fn tokenize(input: &str) -> Result<Vec<(Token, usize)>, ExpressionError> {
106 let mut tokens = Vec::new();
107 let mut chars = input.chars().zip(1..).peekable();
108 let mut last = 0;
109 while let Some((c, position)) = chars.next() {
110 last = position;
111 let token = match c {
112 c if c.is_whitespace() => continue,
113 '+' => Token::Plus,
114 '-' => Token::Minus,
115 '*' => Token::Star,
116 '/' => Token::Slash,
117 '(' => Token::Open,
118 ')' => Token::Close,
119 c if c.is_ascii_alphabetic() || c == '_' => {
120 let mut name = String::from(c.to_ascii_lowercase());
121 while let Some(&(next, at)) = chars.peek() {
122 if !(next.is_ascii_alphanumeric() || next == '_') {
123 break;
124 }
125 name.push(next.to_ascii_lowercase());
126 last = at;
127 chars.next();
128 }
129 Token::Column(name)
130 }
131 c if c.is_ascii_digit() => {
132 let mut text = String::from(c);
133 take_digits(&mut chars, &mut text, &mut last);
134 if let Some(&('.', dot)) = chars.peek() {
135 text.push('.');
136 last = dot;
137 chars.next();
138 let before = text.len();
139 take_digits(&mut chars, &mut text, &mut last);
140 if text.len() == before {
141 return Err(error(dot, ExpressionErrorKind::IncompleteNumber));
142 }
143 }
144 Token::Number(text)
145 }
146 other => {
147 return Err(error(
148 position,
149 ExpressionErrorKind::UnexpectedCharacter(other),
150 ));
151 }
152 };
153 tokens.push((token, position));
154 }
155 tokens.push((Token::End, last + 1));
156 Ok(tokens)
157}
158
159fn take_digits(
160 chars: &mut std::iter::Peekable<impl Iterator<Item = (char, usize)>>,
161 text: &mut String,
162 last: &mut usize,
163) {
164 while let Some(&(next, at)) = chars.peek() {
165 if !next.is_ascii_digit() {
166 break;
167 }
168 text.push(next);
169 *last = at;
170 chars.next();
171 }
172}
173
174struct Node {
176 expression: Expression,
177 height: usize,
178}
179
180struct Parser {
181 tokens: Vec<(Token, usize)>,
182 next: usize,
183}
184
185pub(super) fn parse(input: &str) -> Result<Expression, ExpressionError> {
186 if let Ok(column) = ColumnName::try_new(input) {
187 return Ok(Expression::Column(column));
188 }
189 let mut parser = Parser {
190 tokens: tokenize(input)?,
191 next: 0,
192 };
193 if let (Token::End, _) = parser.peek() {
194 return Err(error(1, ExpressionErrorKind::Empty));
195 }
196 let node = parser.expression(0)?;
197 match parser.peek() {
198 (Token::End, _) => Ok(node.expression),
199 (Token::Close, position) => Err(error(position, ExpressionErrorKind::UnmatchedParenthesis)),
200 (token, position) => Err(error(
201 position,
202 ExpressionErrorKind::ExpectedOperator(token.to_string()),
203 )),
204 }
205}
206
207impl Parser {
208 fn peek(&self) -> (Token, usize) {
209 self.tokens
210 .get(self.next)
211 .or_else(|| self.tokens.last())
212 .cloned()
213 .unwrap_or((Token::End, 1))
214 }
215
216 fn advance(&mut self) {
217 self.next += 1;
218 }
219
220 fn expression(&mut self, depth: usize) -> Result<Node, ExpressionError> {
221 let mut left = self.term(depth)?;
222 loop {
223 let (op, position) = match self.peek() {
224 (Token::Plus, position) => (BinaryOp::Add, position),
225 (Token::Minus, position) => (BinaryOp::Subtract, position),
226 _ => return Ok(left),
227 };
228 self.advance();
229 let right = self.term(depth)?;
230 left = binary(op, left, right, position)?;
231 }
232 }
233
234 fn term(&mut self, depth: usize) -> Result<Node, ExpressionError> {
235 let mut left = self.unary(depth)?;
236 loop {
237 let (op, position) = match self.peek() {
238 (Token::Star, position) => (BinaryOp::Multiply, position),
239 (Token::Slash, position) => (BinaryOp::Divide, position),
240 _ => return Ok(left),
241 };
242 self.advance();
243 let right = self.unary(depth)?;
244 left = binary(op, left, right, position)?;
245 }
246 }
247
248 fn unary(&mut self, depth: usize) -> Result<Node, ExpressionError> {
249 let (Token::Minus, position) = self.peek() else {
250 return self.primary(depth);
251 };
252 let depth = deeper(depth, position)?;
253 self.advance();
254 let inner = self.unary(depth)?;
255 let height = taller(inner.height, position)?;
256 Ok(Node {
257 expression: Expression::Negate(Box::new(inner.expression)),
258 height,
259 })
260 }
261
262 fn primary(&mut self, depth: usize) -> Result<Node, ExpressionError> {
263 let (token, position) = self.peek();
264 let expression = match token {
265 Token::Column(name) => match ColumnName::try_new(&name) {
266 Ok(column) => Expression::Column(column),
267 Err(_) => {
268 return Err(error(position, ExpressionErrorKind::InvalidColumn(name)));
269 }
270 },
271 Token::Number(text) => Expression::Number(NumberLiteral(text)),
272 Token::Open => {
273 let depth = deeper(depth, position)?;
274 self.advance();
275 let inner = self.expression(depth)?;
276 return match self.peek() {
277 (Token::Close, _) => {
278 self.advance();
279 Ok(inner)
280 }
281 (Token::End, _) => {
282 Err(error(position, ExpressionErrorKind::UnclosedParenthesis))
283 }
284 (token, at) => Err(error(
285 at,
286 ExpressionErrorKind::ExpectedOperator(token.to_string()),
287 )),
288 };
289 }
290 other => {
291 return Err(error(
292 position,
293 ExpressionErrorKind::ExpectedOperand(other.to_string()),
294 ));
295 }
296 };
297 self.advance();
298 Ok(Node {
299 expression,
300 height: 0,
301 })
302 }
303}
304
305fn binary(op: BinaryOp, left: Node, right: Node, position: usize) -> Result<Node, ExpressionError> {
306 let height = taller(left.height.max(right.height), position)?;
307 Ok(Node {
308 expression: Expression::Binary {
309 op,
310 left: Box::new(left.expression),
311 right: Box::new(right.expression),
312 },
313 height,
314 })
315}
316
317fn deeper(depth: usize, position: usize) -> Result<usize, ExpressionError> {
318 if depth >= MAX_DEPTH {
319 return Err(error(position, ExpressionErrorKind::TooDeep));
320 }
321 Ok(depth + 1)
322}
323
324fn taller(height: usize, position: usize) -> Result<usize, ExpressionError> {
325 if height >= MAX_DEPTH {
326 return Err(error(position, ExpressionErrorKind::TooDeep));
327 }
328 Ok(height + 1)
329}