Skip to main content

alopex_sql/parser/
expr.rs

1use crate::ast::{BinaryOp, Expr, ExprKind, Literal, Spanned, UnaryOp};
2use crate::error::{ParserError, Result};
3use crate::tokenizer::keyword::Keyword;
4use crate::tokenizer::token::{Token, Word};
5
6use super::Parser;
7use super::precedence::{PREC_UNKNOWN, Precedence};
8
9impl<'a> Parser<'a> {
10    pub(crate) fn parse_subexpr(&mut self, precedence: u8) -> Result<Expr> {
11        let _guard = self.recursion.try_decrease()?;
12
13        let mut expr = self.parse_prefix()?;
14
15        loop {
16            let next_prec = self.next_precedence();
17            if precedence >= next_prec || next_prec == PREC_UNKNOWN {
18                break;
19            }
20            expr = self.parse_infix(expr, next_prec)?;
21        }
22
23        Ok(expr)
24    }
25
26    fn parse_prefix(&mut self) -> Result<Expr> {
27        if let Some(res) = self.dialect.parse_prefix(self) {
28            return res;
29        }
30
31        let token = self.peek().clone();
32        match &token.token {
33            Token::Number(n) => {
34                self.advance();
35                Ok(Expr::new(
36                    ExprKind::Literal(Literal::Number(n.clone())),
37                    token.span,
38                ))
39            }
40            Token::SingleQuotedString(s) => {
41                self.advance();
42                Ok(Expr::new(
43                    ExprKind::Literal(Literal::String(s.clone())),
44                    token.span,
45                ))
46            }
47            Token::Word(Word { keyword, value, .. }) => match keyword {
48                Keyword::TRUE => {
49                    self.advance();
50                    Ok(Expr::new(
51                        ExprKind::Literal(Literal::Boolean(true)),
52                        token.span,
53                    ))
54                }
55                Keyword::FALSE => {
56                    self.advance();
57                    Ok(Expr::new(
58                        ExprKind::Literal(Literal::Boolean(false)),
59                        token.span,
60                    ))
61                }
62                Keyword::NULL => {
63                    self.advance();
64                    Ok(Expr::new(ExprKind::Literal(Literal::Null), token.span))
65                }
66                Keyword::NOT => {
67                    self.advance();
68                    let operand =
69                        self.parse_subexpr(self.dialect.prec_value(Precedence::UnaryNot))?;
70                    let span = token.span.union(&operand.span());
71                    Ok(Expr::new(
72                        ExprKind::UnaryOp {
73                            op: UnaryOp::Not,
74                            operand: Box::new(operand),
75                        },
76                        span,
77                    ))
78                }
79                Keyword::NoKeyword => {
80                    // Identifier or function call
81                    self.advance();
82                    let ident_span = token.span;
83                    if let Token::LParen = self.peek().token {
84                        self.advance(); // consume '('
85                        let mut args = Vec::new();
86                        let mut distinct = false;
87                        let mut star = false;
88                        if !matches!(self.peek().token, Token::RParen) {
89                            if matches!(self.peek().token, Token::Mul) {
90                                self.advance();
91                                star = true;
92                            } else {
93                                if self.consume_keyword(Keyword::DISTINCT) {
94                                    distinct = true;
95                                }
96                                loop {
97                                    args.push(self.parse_subexpr(PREC_UNKNOWN)?);
98                                    if matches!(self.peek().token, Token::Comma) {
99                                        self.advance();
100                                        continue;
101                                    }
102                                    break;
103                                }
104                            }
105                        }
106                        self.expect_token("')'", |t| matches!(t, Token::RParen))?;
107                        let end_span = self.prev().map(|t| t.span).unwrap_or(ident_span);
108                        Ok(Expr::new(
109                            ExprKind::FunctionCall {
110                                name: value.clone(),
111                                args,
112                                distinct,
113                                star,
114                            },
115                            ident_span.union(&end_span),
116                        ))
117                    } else if matches!(self.peek().token, Token::Period) {
118                        self.advance(); // consume '.'
119                        let second = self.expect_token("identifier", |t| {
120                            matches!(
121                                t,
122                                Token::Word(Word {
123                                    keyword: Keyword::NoKeyword,
124                                    ..
125                                })
126                            )
127                        })?;
128                        let end_span = second.span;
129                        let col = match second.token {
130                            Token::Word(Word { value, .. }) => value,
131                            _ => unreachable!(),
132                        };
133                        Ok(Expr::new(
134                            ExprKind::ColumnRef {
135                                table: Some(value.clone()),
136                                column: col,
137                            },
138                            ident_span.union(&end_span),
139                        ))
140                    } else {
141                        Ok(Expr::new(
142                            ExprKind::ColumnRef {
143                                table: None,
144                                column: value.clone(),
145                            },
146                            ident_span,
147                        ))
148                    }
149                }
150                _ => Err(ParserError::UnexpectedToken {
151                    line: token.span.start.line,
152                    column: token.span.start.column,
153                    expected: "identifier or literal".into(),
154                    found: format!("{:?}", token.token),
155                }),
156            },
157            Token::LParen => {
158                self.advance();
159                let expr = self.parse_subexpr(PREC_UNKNOWN)?;
160                self.expect_token("')'", |t| matches!(t, Token::RParen))?;
161                let end_span = self.prev().map(|t| t.span).unwrap_or(expr.span());
162                Ok(Expr::new(expr.kind.clone(), expr.span().union(&end_span)))
163            }
164            Token::Minus => {
165                self.advance();
166                let operand = self.parse_subexpr(self.dialect.prec_value(Precedence::UnaryNot))?;
167                let span = token.span.union(&operand.span());
168                Ok(Expr::new(
169                    ExprKind::UnaryOp {
170                        op: UnaryOp::Minus,
171                        operand: Box::new(operand),
172                    },
173                    span,
174                ))
175            }
176            _ => Err(ParserError::UnexpectedToken {
177                line: token.span.start.line,
178                column: token.span.start.column,
179                expected: "expression".into(),
180                found: format!("{:?}", token.token),
181            }),
182        }
183    }
184
185    pub(crate) fn parse_vector_literal(&mut self) -> Result<Expr> {
186        let start = self.peek().span;
187        self.advance(); // consume '['
188
189        let mut values = Vec::new();
190        if matches!(self.peek().token, Token::RBracket) {
191            return Err(ParserError::InvalidVector {
192                line: start.start.line,
193                column: start.start.column,
194            });
195        }
196        loop {
197            let sign = if matches!(self.peek().token, Token::Minus) {
198                self.advance();
199                -1.0
200            } else {
201                1.0
202            };
203
204            let tok = self.expect_token("number", |t| matches!(t, Token::Number(_)))?;
205            let num = match tok.token {
206                Token::Number(n) => n.parse::<f64>().map_err(|_| ParserError::InvalidVector {
207                    line: tok.span.start.line,
208                    column: tok.span.start.column,
209                })?,
210                _ => unreachable!(),
211            } * sign;
212            values.push(num);
213            if matches!(self.peek().token, Token::Comma) {
214                self.advance();
215                continue;
216            }
217            break;
218        }
219        let end = self
220            .expect_token("']'", |t| matches!(t, Token::RBracket))?
221            .span;
222
223        Ok(Expr::new(
224            ExprKind::VectorLiteral(values),
225            start.union(&end),
226        ))
227    }
228
229    fn parse_infix(&mut self, left: Expr, precedence: u8) -> Result<Expr> {
230        let op_token = self.peek().clone();
231        match &op_token.token {
232            Token::Plus
233            | Token::Minus
234            | Token::Mul
235            | Token::Div
236            | Token::Mod
237            | Token::StringConcat => {
238                self.advance();
239                let op = match op_token.token {
240                    Token::Plus => BinaryOp::Add,
241                    Token::Minus => BinaryOp::Sub,
242                    Token::Mul => BinaryOp::Mul,
243                    Token::Div => BinaryOp::Div,
244                    Token::Mod => BinaryOp::Mod,
245                    Token::StringConcat => BinaryOp::StringConcat,
246                    _ => unreachable!(),
247                };
248                let right = self.parse_subexpr(precedence)?;
249                let span = left.span().union(&right.span());
250                Ok(Expr::new(
251                    ExprKind::BinaryOp {
252                        left: Box::new(left),
253                        op,
254                        right: Box::new(right),
255                    },
256                    span,
257                ))
258            }
259            Token::Eq | Token::Neq | Token::Lt | Token::Gt | Token::LtEq | Token::GtEq => {
260                self.advance();
261                let op = match op_token.token {
262                    Token::Eq => BinaryOp::Eq,
263                    Token::Neq => BinaryOp::Neq,
264                    Token::Lt => BinaryOp::Lt,
265                    Token::Gt => BinaryOp::Gt,
266                    Token::LtEq => BinaryOp::LtEq,
267                    Token::GtEq => BinaryOp::GtEq,
268                    _ => unreachable!(),
269                };
270                let right = self.parse_subexpr(precedence)?;
271                let span = left.span().union(&right.span());
272                Ok(Expr::new(
273                    ExprKind::BinaryOp {
274                        left: Box::new(left),
275                        op,
276                        right: Box::new(right),
277                    },
278                    span,
279                ))
280            }
281            Token::Word(Word { keyword, .. }) => match keyword {
282                Keyword::AND | Keyword::OR => {
283                    self.advance();
284                    let op = if *keyword == Keyword::AND {
285                        BinaryOp::And
286                    } else {
287                        BinaryOp::Or
288                    };
289                    let right = self.parse_subexpr(precedence)?;
290                    let span = left.span().union(&right.span());
291                    Ok(Expr::new(
292                        ExprKind::BinaryOp {
293                            left: Box::new(left),
294                            op,
295                            right: Box::new(right),
296                        },
297                        span,
298                    ))
299                }
300                Keyword::BETWEEN => {
301                    self.advance();
302                    let low = self.parse_subexpr(self.dialect.prec_value(Precedence::Between))?;
303                    self.expect_keyword("AND", Keyword::AND)?;
304                    let high = self.parse_subexpr(self.dialect.prec_value(Precedence::Between))?;
305                    let span = left.span().union(&high.span());
306                    Ok(Expr::new(
307                        ExprKind::Between {
308                            expr: Box::new(left),
309                            low: Box::new(low),
310                            high: Box::new(high),
311                            negated: false,
312                        },
313                        span,
314                    ))
315                }
316                Keyword::LIKE => {
317                    self.advance();
318                    let pattern = self.parse_subexpr(self.dialect.prec_value(Precedence::Like))?;
319                    let escape = if self.consume_keyword(Keyword::ESCAPE) {
320                        Some(Box::new(
321                            self.parse_subexpr(self.dialect.prec_value(Precedence::Like))?,
322                        ))
323                    } else {
324                        None
325                    };
326                    let span = left.span().union(&pattern.span());
327                    let span = if let Some(ref esc) = escape {
328                        span.union(&esc.span())
329                    } else {
330                        span
331                    };
332                    Ok(Expr::new(
333                        ExprKind::Like {
334                            expr: Box::new(left),
335                            pattern: Box::new(pattern),
336                            escape,
337                            negated: false,
338                        },
339                        span,
340                    ))
341                }
342                Keyword::IN => {
343                    self.advance();
344                    self.expect_token("'('", |t| matches!(t, Token::LParen))?;
345                    let mut list = Vec::new();
346                    if !matches!(self.peek().token, Token::RParen) {
347                        loop {
348                            list.push(self.parse_subexpr(PREC_UNKNOWN)?);
349                            if matches!(self.peek().token, Token::Comma) {
350                                self.advance();
351                                continue;
352                            }
353                            break;
354                        }
355                    }
356                    let end_span = self
357                        .expect_token("')'", |t| matches!(t, Token::RParen))?
358                        .span;
359                    let span = left.span().union(&end_span);
360                    Ok(Expr::new(
361                        ExprKind::InList {
362                            expr: Box::new(left),
363                            list,
364                            negated: false,
365                        },
366                        span,
367                    ))
368                }
369                Keyword::IS => {
370                    self.advance();
371                    let negated = self.consume_keyword(Keyword::NOT);
372                    self.expect_keyword("NULL", Keyword::NULL)?;
373                    let span = left.span().union(&self.prev().unwrap().span);
374                    Ok(Expr::new(
375                        ExprKind::IsNull {
376                            expr: Box::new(left),
377                            negated,
378                        },
379                        span,
380                    ))
381                }
382                Keyword::NOT => {
383                    // NOT BETWEEN / NOT LIKE / NOT IN
384                    if let Some(next_kw) = self.peek_keyword_ahead(1) {
385                        match next_kw {
386                            Keyword::BETWEEN => {
387                                self.advance(); // NOT
388                                self.advance(); // BETWEEN
389                                let low = self
390                                    .parse_subexpr(self.dialect.prec_value(Precedence::Between))?;
391                                self.expect_keyword("AND", Keyword::AND)?;
392                                let high = self
393                                    .parse_subexpr(self.dialect.prec_value(Precedence::Between))?;
394                                let span = left.span().union(&high.span());
395                                return Ok(Expr::new(
396                                    ExprKind::Between {
397                                        expr: Box::new(left),
398                                        low: Box::new(low),
399                                        high: Box::new(high),
400                                        negated: true,
401                                    },
402                                    span,
403                                ));
404                            }
405                            Keyword::LIKE => {
406                                self.advance(); // NOT
407                                self.advance(); // LIKE
408                                let pattern =
409                                    self.parse_subexpr(self.dialect.prec_value(Precedence::Like))?;
410                                let escape = if self.consume_keyword(Keyword::ESCAPE) {
411                                    Some(Box::new(self.parse_subexpr(
412                                        self.dialect.prec_value(Precedence::Like),
413                                    )?))
414                                } else {
415                                    None
416                                };
417                                let span = left.span().union(&pattern.span());
418                                let span = if let Some(ref esc) = escape {
419                                    span.union(&esc.span())
420                                } else {
421                                    span
422                                };
423                                return Ok(Expr::new(
424                                    ExprKind::Like {
425                                        expr: Box::new(left),
426                                        pattern: Box::new(pattern),
427                                        escape,
428                                        negated: true,
429                                    },
430                                    span,
431                                ));
432                            }
433                            Keyword::IN => {
434                                self.advance(); // NOT
435                                self.advance(); // IN
436                                self.expect_token("'('", |t| matches!(t, Token::LParen))?;
437                                let mut list = Vec::new();
438                                if !matches!(self.peek().token, Token::RParen) {
439                                    loop {
440                                        list.push(self.parse_subexpr(PREC_UNKNOWN)?);
441                                        if matches!(self.peek().token, Token::Comma) {
442                                            self.advance();
443                                            continue;
444                                        }
445                                        break;
446                                    }
447                                }
448                                let end_span = self
449                                    .expect_token("')'", |t| matches!(t, Token::RParen))?
450                                    .span;
451                                let span = left.span().union(&end_span);
452                                return Ok(Expr::new(
453                                    ExprKind::InList {
454                                        expr: Box::new(left),
455                                        list,
456                                        negated: true,
457                                    },
458                                    span,
459                                ));
460                            }
461                            _ => {}
462                        }
463                    }
464                    Err(ParserError::UnexpectedToken {
465                        line: op_token.span.start.line,
466                        column: op_token.span.start.column,
467                        expected: "BETWEEN, LIKE, IN".into(),
468                        found: "NOT".into(),
469                    })
470                }
471                _ => Err(ParserError::UnexpectedToken {
472                    line: op_token.span.start.line,
473                    column: op_token.span.start.column,
474                    expected: "operator".into(),
475                    found: format!("{:?}", op_token.token),
476                }),
477            },
478            _ => Err(ParserError::UnexpectedToken {
479                line: op_token.span.start.line,
480                column: op_token.span.start.column,
481                expected: "operator".into(),
482                found: format!("{:?}", op_token.token),
483            }),
484        }
485    }
486}