1use fsqlite_ast::{
20 BinaryOp, ColumnRef, Expr, FunctionArgs, InSet, JsonArrow, LikeOp, Literal, PlaceholderType,
21 RaiseAction, SelectStatement, Span, TypeName, UnaryOp, WindowSpec,
22};
23use std::sync::Arc;
24
25use crate::parser::{ParseError, Parser, is_nonreserved_kw, kw_to_str};
26use crate::token::{Token, TokenKind};
27
28mod bp {
31 pub const OR: (u8, u8) = (1, 2);
33 pub const AND: (u8, u8) = (3, 4);
34 pub const NOT_PREFIX: u8 = 5;
36 pub const EQUALITY: (u8, u8) = (7, 8);
38 pub const COMPARISON: (u8, u8) = (9, 10);
40 pub const BITWISE: (u8, u8) = (13, 14);
42 pub const ADD: (u8, u8) = (15, 16);
44 pub const MUL: (u8, u8) = (17, 18);
46 pub const CONCAT: (u8, u8) = (19, 20);
48 pub const COLLATE: u8 = 21;
50 pub const UNARY: u8 = 23;
52 pub const JSON: (u8, u8) = (19, 20);
54}
55
56impl Parser {
57 pub fn parse_expr(&mut self) -> Result<Expr, ParseError> {
59 self.parse_expr_bp(0)
60 }
61
62 fn parse_expr_bp(&mut self, min_bp: u8) -> Result<Expr, ParseError> {
65 self.with_recursion_guard(|p| p.parse_expr_bp_inner(min_bp))
66 }
67
68 fn parse_expr_bp_inner(&mut self, min_bp: u8) -> Result<Expr, ParseError> {
69 let mut lhs = self.parse_prefix()?;
70
71 loop {
72 if let Some(l_bp) = self.postfix_bp() {
74 if l_bp < min_bp {
75 break;
76 }
77 lhs = self.parse_postfix(lhs)?;
78 continue;
79 }
80
81 if let Some((l_bp, r_bp)) = self.infix_bp() {
83 if l_bp < min_bp {
84 break;
85 }
86 lhs = self.parse_infix(lhs, r_bp)?;
87 continue;
88 }
89
90 break;
91 }
92
93 Ok(lhs)
94 }
95
96 fn peek_kind(&self) -> &TokenKind {
99 self.tokens
100 .get(self.pos)
101 .map_or(&TokenKind::Eof, |t| &t.kind)
102 }
103
104 #[allow(dead_code)]
105 fn peek_span(&self) -> Span {
106 self.tokens.get(self.pos).map_or(Span::ZERO, |t| t.span)
107 }
108
109 fn peek_token(&self) -> Option<&Token> {
110 self.tokens.get(self.pos)
111 }
112
113 fn peek_nth_token(&self, offset: usize) -> Option<&Token> {
114 self.tokens.get(self.pos + offset)
115 }
116
117 fn advance_token(&mut self) -> Token {
118 let tok = self.tokens[self.pos].clone();
119 if tok.kind != TokenKind::Eof {
120 self.pos += 1;
121 }
122 tok
123 }
124
125 fn at_kind(&self, kind: &TokenKind) -> bool {
126 std::mem::discriminant(self.peek_kind()) == std::mem::discriminant(kind)
127 }
128
129 fn eat_kind(&mut self, kind: &TokenKind) -> bool {
130 if self.at_kind(kind) {
131 self.advance_token();
132 true
133 } else {
134 false
135 }
136 }
137
138 fn expect_kind(&mut self, expected: &TokenKind) -> Result<Span, ParseError> {
139 if self.at_kind(expected) {
140 Ok(self.advance_token().span)
141 } else {
142 Err(self.err_here(format!("expected {expected:?}, got {:?}", self.peek_kind())))
143 }
144 }
145
146 fn err_here(&self, message: impl Into<String>) -> ParseError {
147 ParseError::at(message, self.peek_token())
148 }
149
150 #[allow(clippy::too_many_lines)]
153 fn parse_prefix(&mut self) -> Result<Expr, ParseError> {
154 let tok = self.advance_token();
155 match &tok.kind {
156 TokenKind::Integer(i) => Ok(Expr::Literal(Literal::Integer(*i), tok.span)),
158 TokenKind::OversizedInt(s) => match s.parse::<f64>() {
159 Ok(v) if v.is_finite() => Ok(Expr::Literal(Literal::Float(v), tok.span)),
160 Ok(_) => Ok(Expr::Literal(Literal::Float(f64::MAX), tok.span)),
161 Err(_) => Err(ParseError::at("integer out of range", Some(&tok))),
162 },
163 TokenKind::Float(f) => Ok(Expr::Literal(Literal::Float(*f), tok.span)),
164 TokenKind::String(s) => Ok(Expr::Literal(Literal::String(s.clone()), tok.span)),
165 TokenKind::Blob(b) => Ok(Expr::Literal(Literal::Blob(b.clone()), tok.span)),
166 TokenKind::KwNull => Ok(Expr::Literal(Literal::Null, tok.span)),
167 TokenKind::KwTrue => Ok(Expr::Literal(Literal::True, tok.span)),
168 TokenKind::KwFalse => Ok(Expr::Literal(Literal::False, tok.span)),
169 TokenKind::KwCurrentTime => Ok(Expr::Literal(Literal::CurrentTime, tok.span)),
170 TokenKind::KwCurrentDate => Ok(Expr::Literal(Literal::CurrentDate, tok.span)),
171 TokenKind::KwCurrentTimestamp => Ok(Expr::Literal(Literal::CurrentTimestamp, tok.span)),
172
173 TokenKind::Question => Ok(Expr::Placeholder(PlaceholderType::Anonymous, tok.span)),
175 TokenKind::QuestionNum(n) => {
176 Ok(Expr::Placeholder(PlaceholderType::Numbered(*n), tok.span))
177 }
178 TokenKind::ColonParam(s) => Ok(Expr::Placeholder(
179 PlaceholderType::ColonNamed(s.clone()),
180 tok.span,
181 )),
182 TokenKind::AtParam(s) => Ok(Expr::Placeholder(
183 PlaceholderType::AtNamed(s.clone()),
184 tok.span,
185 )),
186 TokenKind::DollarParam(s) => Ok(Expr::Placeholder(
187 PlaceholderType::DollarNamed(s.clone()),
188 tok.span,
189 )),
190
191 TokenKind::Minus => {
193 if let TokenKind::OversizedInt(s) = self.peek_kind() {
195 if s == "9223372036854775808" {
196 let num_span = self.advance_token().span;
197 let span = tok.span.merge(num_span);
198 return Ok(Expr::Literal(Literal::Integer(i64::MIN), span));
199 }
200 }
201 let inner = self.parse_expr_bp(bp::UNARY)?;
202 let span = tok.span.merge(inner.span());
203 Ok(Expr::UnaryOp {
204 op: UnaryOp::Negate,
205 expr: Box::new(inner),
206 span,
207 })
208 }
209 TokenKind::Plus => {
210 let inner = self.parse_expr_bp(bp::UNARY)?;
211 let span = tok.span.merge(inner.span());
212 Ok(Expr::UnaryOp {
213 op: UnaryOp::Plus,
214 expr: Box::new(inner),
215 span,
216 })
217 }
218 TokenKind::Tilde => {
219 let inner = self.parse_expr_bp(bp::UNARY)?;
220 let span = tok.span.merge(inner.span());
221 Ok(Expr::UnaryOp {
222 op: UnaryOp::BitNot,
223 expr: Box::new(inner),
224 span,
225 })
226 }
227
228 TokenKind::KwNot => {
230 if matches!(self.peek_kind(), TokenKind::KwExists) {
232 self.advance_token();
233 self.expect_kind(&TokenKind::LeftParen)?;
234 let subquery = self.parse_subquery_minimal()?;
235 let end = self.expect_kind(&TokenKind::RightParen)?;
236 let span = tok.span.merge(end);
237 return Ok(Expr::Exists {
238 subquery: Box::new(subquery),
239 not: true,
240 span,
241 });
242 }
243 let inner = self.parse_expr_bp(bp::NOT_PREFIX)?;
244 let span = tok.span.merge(inner.span());
245 Ok(Expr::UnaryOp {
246 op: UnaryOp::Not,
247 expr: Box::new(inner),
248 span,
249 })
250 }
251
252 TokenKind::KwExists => {
254 self.expect_kind(&TokenKind::LeftParen)?;
255 let subquery = self.parse_subquery_minimal()?;
256 let end = self.expect_kind(&TokenKind::RightParen)?;
257 let span = tok.span.merge(end);
258 Ok(Expr::Exists {
259 subquery: Box::new(subquery),
260 not: false,
261 span,
262 })
263 }
264
265 TokenKind::KwCast => {
267 self.expect_kind(&TokenKind::LeftParen)?;
268 let inner = self.parse_expr()?;
269 self.expect_kind(&TokenKind::KwAs)?;
270 let type_name = self.parse_type_name()?;
271 let end = self.expect_kind(&TokenKind::RightParen)?;
272 let span = tok.span.merge(end);
273 Ok(Expr::Cast {
274 expr: Box::new(inner),
275 type_name,
276 span,
277 })
278 }
279
280 TokenKind::KwCase => self.parse_case_expr(tok.span),
282
283 TokenKind::KwRaise => {
285 self.expect_kind(&TokenKind::LeftParen)?;
286 let (action, message) = self.parse_raise_args()?;
287 let end = self.expect_kind(&TokenKind::RightParen)?;
288 let span = tok.span.merge(end);
289 Ok(Expr::Raise {
290 action,
291 message,
292 span,
293 })
294 }
295
296 TokenKind::LeftParen => {
298 if matches!(
299 self.peek_kind(),
300 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
301 ) {
302 let subquery = self.parse_subquery_minimal()?;
303 let end = self.expect_kind(&TokenKind::RightParen)?;
304 let span = tok.span.merge(end);
305 return Ok(Expr::Subquery(Box::new(subquery), span));
306 }
307 let first = self.parse_expr()?;
308 if self.eat_kind(&TokenKind::Comma) {
309 let mut exprs = vec![first];
310 loop {
311 exprs.push(self.parse_expr()?);
312 if !self.eat_kind(&TokenKind::Comma) {
313 break;
314 }
315 }
316 let end = self.expect_kind(&TokenKind::RightParen)?;
317 let span = tok.span.merge(end);
318 Ok(Expr::RowValue(exprs, span))
319 } else {
320 self.expect_kind(&TokenKind::RightParen)?;
321 Ok(first)
322 }
323 }
324
325 TokenKind::Id(name) | TokenKind::QuotedId(name, _) => {
327 self.parse_ident_expr(Arc::clone(name), tok.span)
328 }
329
330 TokenKind::KwReplace if matches!(self.peek_kind(), TokenKind::LeftParen) => {
332 self.parse_function_call("replace".to_owned(), tok.span)
333 }
334
335 k if is_nonreserved_kw(k) => {
339 let name = kw_to_str(k);
340 self.parse_ident_expr(name, tok.span)
341 }
342
343 _ => Err(ParseError::at(
344 format!("unexpected token in expression: {:?}", tok.kind),
345 Some(&tok),
346 )),
347 }
348 }
349
350 fn parse_ident_expr<S>(&mut self, name: S, start: Span) -> Result<Expr, ParseError>
352 where
353 S: AsRef<str> + Into<Arc<str>>,
354 {
355 if matches!(self.peek_kind(), TokenKind::LeftParen) {
357 return self.parse_function_call(name.as_ref().to_owned(), start);
358 }
359 let name = name.into();
360 if matches!(self.peek_kind(), TokenKind::Dot) {
362 let Some(col_tok) = self.peek_nth_token(1) else {
363 return Err(self.err_here("expected column name after '.'"));
364 };
365 let col_name = match &col_tok.kind {
366 TokenKind::Id(c) | TokenKind::QuotedId(c, _) => Arc::clone(c),
367 TokenKind::Star => Arc::<str>::from("*"),
368 k if k.keyword_str().is_some() => Arc::<str>::from(kw_to_str(k)),
371 _ => {
372 return Err(ParseError::at(
373 format!("expected column name after '.', got {:?}", col_tok.kind),
374 Some(col_tok),
375 ));
376 }
377 };
378 let span = start.merge(col_tok.span);
379 self.pos = self.pos.saturating_add(2);
380 return Ok(Expr::Column(ColumnRef::qualified(name, col_name), span));
381 }
382 Ok(Expr::Column(ColumnRef::bare(name), start))
383 }
384
385 fn postfix_bp(&self) -> Option<u8> {
388 match self.peek_kind() {
389 TokenKind::KwCollate => Some(bp::COLLATE),
390 TokenKind::KwIsnull | TokenKind::KwNotnull => Some(bp::EQUALITY.0),
391 TokenKind::KwNot => {
392 if let Some(next) = self.tokens.get(self.pos + 1) {
393 if matches!(next.kind, TokenKind::KwNull) {
394 return Some(bp::EQUALITY.0);
395 }
396 }
397 None
398 }
399 _ => None,
400 }
401 }
402
403 fn parse_postfix(&mut self, lhs: Expr) -> Result<Expr, ParseError> {
404 let tok = self.advance_token();
405 match &tok.kind {
406 TokenKind::KwCollate => {
407 let collation = match self.parse_identifier() {
408 Ok(s) => s,
409 Err(_) => {
410 return Err(self.err_here("expected collation name after COLLATE"));
411 }
412 };
413 let name_span = self.tokens[self.pos.saturating_sub(1)].span;
414 let span = lhs.span().merge(name_span);
415 Ok(Expr::Collate {
416 expr: Box::new(lhs),
417 collation,
418 span,
419 })
420 }
421 TokenKind::KwIsnull => {
422 let span = lhs.span().merge(tok.span);
423 Ok(Expr::IsNull {
424 expr: Box::new(lhs),
425 not: false,
426 span,
427 })
428 }
429 TokenKind::KwNotnull => {
430 let span = lhs.span().merge(tok.span);
431 Ok(Expr::IsNull {
432 expr: Box::new(lhs),
433 not: true,
434 span,
435 })
436 }
437 TokenKind::KwNot => {
438 let null_tok = self.advance_token(); let span = lhs.span().merge(null_tok.span);
440 Ok(Expr::IsNull {
441 expr: Box::new(lhs),
442 not: true,
443 span,
444 })
445 }
446 other => Err(ParseError::at(
447 format!("unexpected postfix token: {other:?}"),
448 Some(&tok),
449 )),
450 }
451 }
452
453 fn infix_bp(&self) -> Option<(u8, u8)> {
456 match self.peek_kind() {
457 TokenKind::KwOr => Some(bp::OR),
458 TokenKind::KwAnd => Some(bp::AND),
459
460 TokenKind::Eq
461 | TokenKind::EqEq
462 | TokenKind::Ne
463 | TokenKind::LtGt
464 | TokenKind::KwIs
465 | TokenKind::KwLike
466 | TokenKind::KwGlob
467 | TokenKind::KwMatch
468 | TokenKind::KwRegexp
469 | TokenKind::KwBetween
470 | TokenKind::KwIn => Some(bp::EQUALITY),
471
472 TokenKind::KwNot => {
474 let next = self.tokens.get(self.pos + 1).map(|t| &t.kind);
475 match next {
476 Some(
477 TokenKind::KwLike
478 | TokenKind::KwGlob
479 | TokenKind::KwMatch
480 | TokenKind::KwRegexp
481 | TokenKind::KwBetween
482 | TokenKind::KwIn,
483 ) => Some(bp::EQUALITY),
484 _ => None,
485 }
486 }
487
488 TokenKind::Lt | TokenKind::Le | TokenKind::Gt | TokenKind::Ge => Some(bp::COMPARISON),
489
490 TokenKind::Ampersand
491 | TokenKind::Pipe
492 | TokenKind::ShiftLeft
493 | TokenKind::ShiftRight => Some(bp::BITWISE),
494
495 TokenKind::Plus | TokenKind::Minus => Some(bp::ADD),
496 TokenKind::Star | TokenKind::Slash | TokenKind::Percent => Some(bp::MUL),
497 TokenKind::Concat => Some(bp::CONCAT),
498 TokenKind::Arrow | TokenKind::DoubleArrow => Some(bp::JSON),
499
500 _ => None,
501 }
502 }
503
504 #[allow(clippy::too_many_lines)]
505 fn parse_infix(&mut self, lhs: Expr, r_bp: u8) -> Result<Expr, ParseError> {
506 let tok = self.advance_token();
507 match &tok.kind {
508 TokenKind::Plus => self.make_binop(lhs, BinaryOp::Add, r_bp),
510 TokenKind::Minus => self.make_binop(lhs, BinaryOp::Subtract, r_bp),
511 TokenKind::Star => self.make_binop(lhs, BinaryOp::Multiply, r_bp),
512 TokenKind::Slash => self.make_binop(lhs, BinaryOp::Divide, r_bp),
513 TokenKind::Percent => self.make_binop(lhs, BinaryOp::Modulo, r_bp),
514 TokenKind::Concat => self.make_binop(lhs, BinaryOp::Concat, r_bp),
515 TokenKind::Eq | TokenKind::EqEq => self.make_binop(lhs, BinaryOp::Eq, r_bp),
516 TokenKind::Ne | TokenKind::LtGt => self.make_binop(lhs, BinaryOp::Ne, r_bp),
517 TokenKind::Lt => self.make_binop(lhs, BinaryOp::Lt, r_bp),
518 TokenKind::Le => self.make_binop(lhs, BinaryOp::Le, r_bp),
519 TokenKind::Gt => self.make_binop(lhs, BinaryOp::Gt, r_bp),
520 TokenKind::Ge => self.make_binop(lhs, BinaryOp::Ge, r_bp),
521 TokenKind::Ampersand => self.make_binop(lhs, BinaryOp::BitAnd, r_bp),
522 TokenKind::Pipe => self.make_binop(lhs, BinaryOp::BitOr, r_bp),
523 TokenKind::ShiftLeft => self.make_binop(lhs, BinaryOp::ShiftLeft, r_bp),
524 TokenKind::ShiftRight => self.make_binop(lhs, BinaryOp::ShiftRight, r_bp),
525 TokenKind::KwOr => self.make_binop(lhs, BinaryOp::Or, r_bp),
526 TokenKind::KwAnd => self.make_binop(lhs, BinaryOp::And, r_bp),
527
528 TokenKind::KwIs => {
530 let not = self.eat_kind(&TokenKind::KwNot);
531 if self.eat_kind(&TokenKind::KwDistinct) {
532 self.expect_kind(&TokenKind::KwFrom)?;
533 let rhs = self.parse_expr_bp(r_bp)?;
534 let span = lhs.span().merge(rhs.span());
535 let op = if not { BinaryOp::Is } else { BinaryOp::IsNot };
538 return Ok(Expr::BinaryOp {
539 left: Box::new(lhs),
540 op,
541 right: Box::new(rhs),
542 span,
543 });
544 }
545 if matches!(self.peek_kind(), TokenKind::KwNull) {
546 let end = self.advance_token().span;
547 let span = lhs.span().merge(end);
548 return Ok(Expr::IsNull {
549 expr: Box::new(lhs),
550 not,
551 span,
552 });
553 }
554 let rhs = self.parse_expr_bp(r_bp)?;
555 let span = lhs.span().merge(rhs.span());
556 let op = if not { BinaryOp::IsNot } else { BinaryOp::Is };
557 Ok(Expr::BinaryOp {
558 left: Box::new(lhs),
559 op,
560 right: Box::new(rhs),
561 span,
562 })
563 }
564
565 TokenKind::KwLike => self.parse_like(lhs, LikeOp::Like, false),
567 TokenKind::KwGlob => self.parse_like(lhs, LikeOp::Glob, false),
568 TokenKind::KwMatch => self.parse_like(lhs, LikeOp::Match, false),
569 TokenKind::KwRegexp => self.parse_like(lhs, LikeOp::Regexp, false),
570
571 TokenKind::KwBetween => self.parse_between(lhs, false),
573
574 TokenKind::KwIn => self.parse_in(lhs, false),
576
577 TokenKind::Arrow => {
579 let rhs = self.parse_expr_bp(r_bp)?;
580 let span = lhs.span().merge(rhs.span());
581 Ok(Expr::JsonAccess {
582 expr: Box::new(lhs),
583 path: Box::new(rhs),
584 arrow: JsonArrow::Arrow,
585 span,
586 })
587 }
588 TokenKind::DoubleArrow => {
589 let rhs = self.parse_expr_bp(r_bp)?;
590 let span = lhs.span().merge(rhs.span());
591 Ok(Expr::JsonAccess {
592 expr: Box::new(lhs),
593 path: Box::new(rhs),
594 arrow: JsonArrow::DoubleArrow,
595 span,
596 })
597 }
598
599 TokenKind::KwNot => {
601 let next = self.advance_token();
602 match &next.kind {
603 TokenKind::KwLike => self.parse_like(lhs, LikeOp::Like, true),
604 TokenKind::KwGlob => self.parse_like(lhs, LikeOp::Glob, true),
605 TokenKind::KwMatch => self.parse_like(lhs, LikeOp::Match, true),
606 TokenKind::KwRegexp => self.parse_like(lhs, LikeOp::Regexp, true),
607 TokenKind::KwBetween => self.parse_between(lhs, true),
608 TokenKind::KwIn => self.parse_in(lhs, true),
609 _ => Err(ParseError::at(
610 format!(
611 "expected LIKE/GLOB/MATCH/REGEXP/BETWEEN/IN \
612 after NOT, got {:?}",
613 next.kind
614 ),
615 Some(&next),
616 )),
617 }
618 }
619
620 other => Err(ParseError::at(
621 format!("unexpected infix token: {other:?}"),
622 Some(&tok),
623 )),
624 }
625 }
626
627 fn make_binop(&mut self, lhs: Expr, op: BinaryOp, r_bp: u8) -> Result<Expr, ParseError> {
628 let rhs = self.parse_expr_bp(r_bp)?;
629 let span = lhs.span().merge(rhs.span());
630 Ok(Expr::BinaryOp {
631 left: Box::new(lhs),
632 op,
633 right: Box::new(rhs),
634 span,
635 })
636 }
637
638 fn parse_like(&mut self, lhs: Expr, op: LikeOp, not: bool) -> Result<Expr, ParseError> {
641 let pattern = self.parse_expr_bp(bp::EQUALITY.1)?;
642 let escape = if self.eat_kind(&TokenKind::KwEscape) {
643 Some(Box::new(self.parse_expr_bp(bp::EQUALITY.1)?))
646 } else {
647 None
648 };
649 let end = escape.as_ref().map_or_else(|| pattern.span(), |e| e.span());
650 let span = lhs.span().merge(end);
651 Ok(Expr::Like {
652 expr: Box::new(lhs),
653 pattern: Box::new(pattern),
654 escape,
655 op,
656 not,
657 span,
658 })
659 }
660
661 fn parse_between(&mut self, lhs: Expr, not: bool) -> Result<Expr, ParseError> {
662 let low = self.parse_expr_bp(bp::NOT_PREFIX)?;
664 if !self.eat_kind(&TokenKind::KwAnd) {
665 return Err(self.err_here("expected AND in BETWEEN expression"));
666 }
667 let high = self.parse_expr_bp(bp::EQUALITY.1)?;
668 let span = lhs.span().merge(high.span());
669 Ok(Expr::Between {
670 expr: Box::new(lhs),
671 low: Box::new(low),
672 high: Box::new(high),
673 not,
674 span,
675 })
676 }
677
678 fn parse_in(&mut self, lhs: Expr, not: bool) -> Result<Expr, ParseError> {
679 let start = lhs.span();
680
681 if !self.at_kind(&TokenKind::LeftParen) {
683 let table = self.parse_qualified_name()?;
684 let end = self.tokens[self.pos.saturating_sub(1)].span;
685 let span = start.merge(end);
686 return Ok(Expr::In {
687 expr: Box::new(lhs),
688 set: InSet::Table(table),
689 not,
690 span,
691 });
692 }
693
694 self.expect_kind(&TokenKind::LeftParen)?;
695
696 if matches!(
697 self.peek_kind(),
698 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
699 ) {
700 let subquery = self.parse_subquery_minimal()?;
701 let end = self.expect_kind(&TokenKind::RightParen)?;
702 let span = start.merge(end);
703 return Ok(Expr::In {
704 expr: Box::new(lhs),
705 set: InSet::Subquery(Box::new(subquery)),
706 not,
707 span,
708 });
709 }
710
711 let mut exprs = Vec::new();
712 if !self.at_kind(&TokenKind::RightParen) {
713 exprs.push(self.parse_expr()?);
714 while self.eat_kind(&TokenKind::Comma) {
715 exprs.push(self.parse_expr()?);
716 }
717 }
718 let end = self.expect_kind(&TokenKind::RightParen)?;
719 let span = start.merge(end);
720 Ok(Expr::In {
721 expr: Box::new(lhs),
722 set: InSet::List(exprs),
723 not,
724 span,
725 })
726 }
727
728 fn parse_case_expr(&mut self, start: Span) -> Result<Expr, ParseError> {
729 let operand = if matches!(self.peek_kind(), TokenKind::KwWhen) {
730 None
731 } else {
732 Some(Box::new(self.parse_expr()?))
733 };
734
735 let mut whens = Vec::new();
736 while self.eat_kind(&TokenKind::KwWhen) {
737 let condition = self.parse_expr()?;
738 if !self.eat_kind(&TokenKind::KwThen) {
739 return Err(self.err_here("expected THEN in CASE expression"));
740 }
741 let result = self.parse_expr()?;
742 whens.push((condition, result));
743 }
744 if whens.is_empty() {
745 return Err(self.err_here("CASE requires at least one WHEN clause"));
746 }
747
748 let else_expr = if self.eat_kind(&TokenKind::KwElse) {
749 Some(Box::new(self.parse_expr()?))
750 } else {
751 None
752 };
753
754 if !self.eat_kind(&TokenKind::KwEnd) {
755 return Err(self.err_here("expected END for CASE expression"));
756 }
757 let end = self.tokens[self.pos.saturating_sub(1)].span;
758 let span = start.merge(end);
759 Ok(Expr::Case {
760 operand,
761 whens,
762 else_expr,
763 span,
764 })
765 }
766
767 fn parse_function_call(&mut self, name: String, start: Span) -> Result<Expr, ParseError> {
768 self.expect_kind(&TokenKind::LeftParen)?;
769
770 let (args, distinct) = if matches!(self.peek_kind(), TokenKind::Star) {
771 if !name.eq_ignore_ascii_case("count") {
772 return Err(self.err_here("'*' can only be used with count() function"));
773 }
774 self.advance_token();
775 (FunctionArgs::Star, false)
776 } else {
777 let distinct = self.eat_kind(&TokenKind::KwDistinct);
778 let args = if matches!(self.peek_kind(), TokenKind::RightParen) {
779 if distinct {
780 return Err(self.err_here("DISTINCT requires at least one argument"));
781 }
782 FunctionArgs::List(Vec::new())
783 } else {
784 let mut list = vec![self.parse_expr()?];
785 while self.eat_kind(&TokenKind::Comma) {
786 list.push(self.parse_expr()?);
787 }
788 FunctionArgs::List(list)
789 };
790 (args, distinct)
791 };
792
793 let order_by = if self.eat_kind(&TokenKind::KwOrder) {
795 self.expect_kind(&TokenKind::KwBy)?;
796 self.parse_comma_sep(Self::parse_ordering_term)?
797 } else {
798 vec![]
799 };
800
801 let mut end = self.expect_kind(&TokenKind::RightParen)?;
802 let filter = if matches!(self.peek_kind(), TokenKind::KwFilter)
805 && self
806 .tokens
807 .get(self.pos + 1)
808 .is_some_and(|t| t.kind == TokenKind::LeftParen)
809 {
810 self.advance_token(); self.expect_kind(&TokenKind::LeftParen)?;
812 self.expect_kind(&TokenKind::KwWhere)?;
813 let predicate = self.parse_expr()?;
814 let filter_end = self.expect_kind(&TokenKind::RightParen)?;
815 end = end.merge(filter_end);
816 Some(Box::new(predicate))
817 } else {
818 None
819 };
820 let over = if matches!(self.peek_kind(), TokenKind::KwOver)
823 && self.tokens.get(self.pos + 1).is_some_and(|t| {
824 matches!(
825 t.kind,
826 TokenKind::LeftParen | TokenKind::Id(_) | TokenKind::QuotedId(_, _)
827 )
828 }) {
829 self.advance_token(); if self.eat_kind(&TokenKind::LeftParen) {
831 let spec = self.parse_window_spec()?;
832 let over_end = self.expect_kind(&TokenKind::RightParen)?;
833 end = end.merge(over_end);
834 Some(spec)
835 } else {
836 let base_window = self.parse_identifier()?;
837 let base_span = self.tokens[self.pos.saturating_sub(1)].span;
838 end = end.merge(base_span);
839 Some(WindowSpec {
840 base_window: Some(base_window),
841 partition_by: Vec::new(),
842 order_by: Vec::new(),
843 frame: None,
844 })
845 }
846 } else {
847 None
848 };
849
850 let span = start.merge(end);
851 Ok(Expr::FunctionCall {
852 name,
853 args,
854 distinct,
855 order_by,
856 filter,
857 over,
858 span,
859 })
860 }
861
862 fn parse_raise_args(&mut self) -> Result<(RaiseAction, Option<String>), ParseError> {
863 let action_tok = self.advance_token();
864 let action = match &action_tok.kind {
865 TokenKind::KwIgnore => RaiseAction::Ignore,
866 TokenKind::KwRollback => RaiseAction::Rollback,
867 TokenKind::KwAbort => RaiseAction::Abort,
868 TokenKind::KwFail => RaiseAction::Fail,
869 _ => {
870 return Err(ParseError::at(
871 "expected IGNORE, ROLLBACK, ABORT, or FAIL in RAISE",
872 Some(&action_tok),
873 ));
874 }
875 };
876 if matches!(action, RaiseAction::Ignore) {
877 return Ok((action, None));
878 }
879 self.expect_kind(&TokenKind::Comma)?;
880 let msg_tok = self.advance_token();
881 let message = match &msg_tok.kind {
882 TokenKind::String(s) => s.clone(),
883 _ => {
884 return Err(ParseError::at(
885 "expected string message in RAISE",
886 Some(&msg_tok),
887 ));
888 }
889 };
890 Ok((action, Some(message)))
891 }
892
893 fn parse_type_name(&mut self) -> Result<TypeName, ParseError> {
894 let mut parts = Vec::new();
895 loop {
896 match self.peek_kind() {
897 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
898 let tok = self.advance_token();
899 if let TokenKind::Id(s) | TokenKind::QuotedId(s, _) = &tok.kind {
900 parts.push(s.to_string());
901 } else {
902 unreachable!();
903 }
904 }
905 k if is_nonreserved_kw(k) => {
906 let tok = self.advance_token();
907 parts.push(kw_to_str(&tok.kind));
908 }
909 _ => break,
910 }
911 }
912 if parts.is_empty() {
913 return Err(self.err_here("expected type name"));
914 }
915 let name = parts.join(" ");
916
917 let (arg1, arg2) = if self.eat_kind(&TokenKind::LeftParen) {
918 let a1 = self.parse_type_arg()?;
919 let a2 = if self.eat_kind(&TokenKind::Comma) {
920 Some(self.parse_type_arg()?)
921 } else {
922 None
923 };
924 self.expect_kind(&TokenKind::RightParen)?;
925 (Some(a1), a2)
926 } else {
927 (None, None)
928 };
929
930 Ok(TypeName { name, arg1, arg2 })
931 }
932
933 fn parse_type_arg(&mut self) -> Result<String, ParseError> {
934 let tok = self.advance_token();
935 match &tok.kind {
936 TokenKind::Integer(i) => Ok(i.to_string()),
937 TokenKind::Float(f) => Ok(f.to_string()),
938 TokenKind::Minus => {
939 let next = self.advance_token();
940 match &next.kind {
941 TokenKind::Integer(i) => Ok(format!("-{i}")),
942 TokenKind::OversizedInt(s) => Ok(format!("-{s}")),
943 TokenKind::Float(f) => Ok(format!("-{f}")),
944 _ => Err(ParseError::at(
945 "expected number in type argument",
946 Some(&next),
947 )),
948 }
949 }
950 TokenKind::Plus => {
951 let next = self.advance_token();
952 match &next.kind {
953 TokenKind::Integer(i) => Ok(format!("+{i}")),
954 TokenKind::OversizedInt(s) => Ok(format!("+{s}")),
955 TokenKind::Float(f) => Ok(format!("+{f}")),
956 _ => Err(ParseError::at(
957 "expected number in type argument",
958 Some(&next),
959 )),
960 }
961 }
962 TokenKind::OversizedInt(s) => Ok(s.clone()),
963 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => Ok(s.to_string()),
964 _ => Err(ParseError::at("expected type argument", Some(&tok))),
965 }
966 }
967
968 fn parse_subquery_minimal(&mut self) -> Result<SelectStatement, ParseError> {
970 let with = if self.at_kind(&TokenKind::KwWith) {
971 Some(self.parse_with_clause()?)
972 } else {
973 None
974 };
975 self.parse_select_stmt(with)
976 }
977}
978
979pub fn parse_expr(sql: &str) -> Result<Expr, ParseError> {
981 let mut parser = Parser::from_sql(sql);
982 let expr = parser.parse_expr()?;
983 if !matches!(parser.peek_kind(), TokenKind::Eof | TokenKind::Semicolon) {
984 return Err(parser.err_here(format!(
985 "unexpected token after expression: {:?}",
986 parser.peek_kind()
987 )));
988 }
989 Ok(expr)
990}
991
992#[cfg(test)]
993mod tests {
994 use super::*;
995 use fsqlite_ast::{SelectCore, TableOrSubquery};
996
997 fn parse(sql: &str) -> Expr {
998 match parse_expr(sql) {
999 Ok(expr) => expr,
1000 Err(err) => unreachable!("parse error for `{sql}`: {err}"),
1001 }
1002 }
1003
1004 #[test]
1007 fn test_not_lower_precedence_than_comparison() {
1008 let expr = parse("NOT x = y");
1010 match &expr {
1011 Expr::UnaryOp {
1012 op: UnaryOp::Not,
1013 expr: inner,
1014 ..
1015 } => match inner.as_ref() {
1016 Expr::BinaryOp {
1017 op: BinaryOp::Eq, ..
1018 } => {}
1019 other => unreachable!("expected Eq inside NOT, got {other:?}"),
1020 },
1021 other => unreachable!("expected NOT(Eq), got {other:?}"),
1022 }
1023 }
1024
1025 #[test]
1026 fn test_unary_binds_tighter_than_collate() {
1027 let expr = parse("-x COLLATE NOCASE");
1029 match &expr {
1030 Expr::Collate {
1031 expr: inner,
1032 collation,
1033 ..
1034 } => {
1035 assert_eq!(collation, "NOCASE");
1036 assert!(matches!(
1037 inner.as_ref(),
1038 Expr::UnaryOp {
1039 op: UnaryOp::Negate,
1040 ..
1041 }
1042 ));
1043 }
1044 other => unreachable!("expected COLLATE(Negate), got {other:?}"),
1045 }
1046 }
1047
1048 #[test]
1049 fn test_arithmetic_precedence() {
1050 let expr = parse("1 + 2 * 3");
1052 match &expr {
1053 Expr::BinaryOp {
1054 op: BinaryOp::Add,
1055 left,
1056 right,
1057 ..
1058 } => {
1059 assert!(matches!(
1060 left.as_ref(),
1061 Expr::Literal(Literal::Integer(1), _)
1062 ));
1063 assert!(matches!(
1064 right.as_ref(),
1065 Expr::BinaryOp {
1066 op: BinaryOp::Multiply,
1067 ..
1068 }
1069 ));
1070 }
1071 other => unreachable!("expected Add(1, Mul(2,3)), got {other:?}"),
1072 }
1073 }
1074
1075 #[test]
1076 fn test_and_higher_than_or() {
1077 let expr = parse("a OR b AND c");
1079 match &expr {
1080 Expr::BinaryOp {
1081 op: BinaryOp::Or,
1082 right,
1083 ..
1084 } => {
1085 assert!(matches!(
1086 right.as_ref(),
1087 Expr::BinaryOp {
1088 op: BinaryOp::And,
1089 ..
1090 }
1091 ));
1092 }
1093 other => unreachable!("expected Or(a, And(b,c)), got {other:?}"),
1094 }
1095 }
1096
1097 #[test]
1100 fn test_cast_expression() {
1101 let expr = parse("CAST(42 AS INTEGER)");
1102 match &expr {
1103 Expr::Cast {
1104 expr: inner,
1105 type_name,
1106 ..
1107 } => {
1108 assert!(matches!(
1109 inner.as_ref(),
1110 Expr::Literal(Literal::Integer(42), _)
1111 ));
1112 assert_eq!(type_name.name, "INTEGER");
1113 }
1114 other => unreachable!("expected Cast, got {other:?}"),
1115 }
1116 }
1117
1118 #[test]
1119 fn test_cast_float_argument() {
1120 let expr = parse("CAST(x AS DECIMAL(10.5, -2.5))");
1122 match &expr {
1123 Expr::Cast { type_name, .. } => {
1124 assert_eq!(type_name.name, "DECIMAL");
1125 assert_eq!(type_name.arg1.as_deref(), Some("10.5"));
1126 assert_eq!(type_name.arg2.as_deref(), Some("-2.5"));
1127 }
1128 other => unreachable!("expected Cast with float args, got {other:?}"),
1129 }
1130 }
1131
1132 #[test]
1133 fn test_cast_signed_args() {
1134 let expr = parse("CAST(x AS NUMERIC(+5, -5))");
1136 match &expr {
1137 Expr::Cast { type_name, .. } => {
1138 assert_eq!(type_name.name, "NUMERIC");
1139 assert_eq!(type_name.arg1.as_deref(), Some("+5"));
1140 assert_eq!(type_name.arg2.as_deref(), Some("-5"));
1141 }
1142 other => unreachable!("expected Cast with signed args, got {other:?}"),
1143 }
1144 }
1145
1146 #[test]
1149 fn test_case_when_simple() {
1150 let expr = parse(
1151 "CASE x WHEN 1 THEN 'one' WHEN 2 THEN 'two' \
1152 ELSE 'other' END",
1153 );
1154 match &expr {
1155 Expr::Case {
1156 operand: Some(op),
1157 whens,
1158 else_expr: Some(_),
1159 ..
1160 } => {
1161 assert!(matches!(op.as_ref(), Expr::Column(..)));
1162 assert_eq!(whens.len(), 2);
1163 }
1164 other => unreachable!("expected simple CASE, got {other:?}"),
1165 }
1166 }
1167
1168 #[test]
1169 fn test_case_when_searched() {
1170 let expr = parse(
1171 "CASE WHEN x > 0 THEN 'pos' WHEN x < 0 THEN 'neg' \
1172 ELSE 'zero' END",
1173 );
1174 match &expr {
1175 Expr::Case {
1176 operand: None,
1177 whens,
1178 else_expr: Some(_),
1179 ..
1180 } => {
1181 assert_eq!(whens.len(), 2);
1182 assert!(matches!(
1183 &whens[0].0,
1184 Expr::BinaryOp {
1185 op: BinaryOp::Gt,
1186 ..
1187 }
1188 ));
1189 }
1190 other => unreachable!("expected searched CASE, got {other:?}"),
1191 }
1192 }
1193
1194 #[test]
1197 fn test_exists_subquery() {
1198 let expr = parse("EXISTS (SELECT 1)");
1199 assert!(matches!(expr, Expr::Exists { not: false, .. }));
1200 }
1201
1202 #[test]
1203 fn test_not_exists_subquery() {
1204 let expr = parse("NOT EXISTS (SELECT 1)");
1205 assert!(matches!(expr, Expr::Exists { not: true, .. }));
1206 }
1207
1208 #[test]
1209 fn test_exists_subquery_supports_qualified_table_with_alias() {
1210 let expr = parse("EXISTS (SELECT 1 FROM main.users AS u WHERE u.id = 1)");
1211 match expr {
1212 Expr::Exists { subquery, .. } => match subquery.body.select {
1213 SelectCore::Select {
1214 from: Some(from), ..
1215 } => match from.source {
1216 TableOrSubquery::Table { name, alias, .. } => {
1217 assert_eq!(name.schema.as_deref(), Some("main"));
1218 assert_eq!(name.name, "users");
1219 assert_eq!(alias.as_deref(), Some("u"));
1220 }
1221 other => unreachable!("expected table source, got {other:?}"),
1222 },
1223 other => unreachable!("expected SELECT core with FROM, got {other:?}"),
1224 },
1225 other => unreachable!("expected EXISTS subquery, got {other:?}"),
1226 }
1227 }
1228
1229 #[test]
1232 fn test_in_expr_list() {
1233 let expr = parse("x IN (1, 2, 3)");
1234 match &expr {
1235 Expr::In {
1236 not: false,
1237 set: InSet::List(items),
1238 ..
1239 } => assert_eq!(items.len(), 3),
1240 other => unreachable!("expected IN list, got {other:?}"),
1241 }
1242 }
1243
1244 #[test]
1245 fn test_in_subquery() {
1246 let expr = parse("x IN (SELECT y FROM t)");
1247 assert!(matches!(
1248 expr,
1249 Expr::In {
1250 not: false,
1251 set: InSet::Subquery(_),
1252 ..
1253 }
1254 ));
1255 }
1256
1257 #[test]
1258 fn test_in_subquery_with_order_by_and_limit() {
1259 let expr =
1261 parse("id NOT IN (SELECT id FROM search_recipes ORDER BY updated_ts DESC LIMIT 5)");
1262 match &expr {
1263 Expr::In {
1264 not: true,
1265 set: InSet::Subquery(stmt),
1266 ..
1267 } => {
1268 assert_eq!(stmt.order_by.len(), 1, "ORDER BY should be parsed");
1269 assert!(stmt.limit.is_some(), "LIMIT should be parsed");
1270 }
1271 other => unreachable!("expected NOT IN subquery, got {other:?}"),
1272 }
1273 }
1274
1275 #[test]
1276 fn test_in_subquery_supports_group_by_and_having() {
1277 let expr = parse("x IN (SELECT y FROM t GROUP BY y HAVING COUNT(*) > 1)");
1278 match expr {
1279 Expr::In {
1280 set: InSet::Subquery(stmt),
1281 ..
1282 } => match stmt.body.select {
1283 SelectCore::Select {
1284 group_by, having, ..
1285 } => {
1286 assert_eq!(group_by.len(), 1, "GROUP BY should be parsed");
1287 assert!(having.is_some(), "HAVING should be parsed");
1288 }
1289 SelectCore::Values(_) => unreachable!("expected SELECT core"),
1290 },
1291 other => unreachable!("expected IN subquery, got {other:?}"),
1292 }
1293 }
1294
1295 #[test]
1296 fn test_not_in() {
1297 let expr = parse("x NOT IN (1, 2)");
1298 assert!(matches!(expr, Expr::In { not: true, .. }));
1299 }
1300
1301 #[test]
1302 fn test_in_table_name() {
1303 let expr = parse("x IN t");
1304 assert!(matches!(
1305 expr,
1306 Expr::In {
1307 not: false,
1308 set: InSet::Table(_),
1309 ..
1310 }
1311 ));
1312 }
1313
1314 #[test]
1315 fn test_not_in_table_name() {
1316 let expr = parse("x NOT IN t");
1317 assert!(matches!(
1318 expr,
1319 Expr::In {
1320 not: true,
1321 set: InSet::Table(_),
1322 ..
1323 }
1324 ));
1325 }
1326
1327 #[test]
1328 fn test_in_schema_table_name() {
1329 let expr = parse("x IN main.t");
1330 match expr {
1331 Expr::In {
1332 set: InSet::Table(name),
1333 ..
1334 } => {
1335 assert_eq!(name.schema.as_deref(), Some("main"));
1336 assert_eq!(name.name, "t");
1337 }
1338 other => unreachable!("expected IN table form, got {other:?}"),
1339 }
1340 }
1341
1342 #[test]
1345 fn test_between_and() {
1346 let expr = parse("x BETWEEN 1 AND 10");
1347 assert!(matches!(expr, Expr::Between { not: false, .. }));
1348 }
1349
1350 #[test]
1351 fn test_not_between() {
1352 let expr = parse("x NOT BETWEEN 1 AND 10");
1353 assert!(matches!(expr, Expr::Between { not: true, .. }));
1354 }
1355
1356 #[test]
1357 fn test_between_does_not_consume_outer_and() {
1358 let expr = parse("x BETWEEN 1 AND 10 AND y = 1");
1360 match &expr {
1361 Expr::BinaryOp {
1362 op: BinaryOp::And,
1363 left,
1364 ..
1365 } => assert!(matches!(left.as_ref(), Expr::Between { .. })),
1366 other => unreachable!("expected AND(BETWEEN, Eq), got {other:?}"),
1367 }
1368 }
1369
1370 #[test]
1373 fn test_like_pattern() {
1374 let expr = parse("name LIKE '%foo%'");
1375 assert!(matches!(
1376 expr,
1377 Expr::Like {
1378 op: LikeOp::Like,
1379 not: false,
1380 escape: None,
1381 ..
1382 }
1383 ));
1384 }
1385
1386 #[test]
1387 fn test_like_escape() {
1388 let expr = parse("name LIKE '%\\%%' ESCAPE '\\'");
1389 assert!(matches!(
1390 expr,
1391 Expr::Like {
1392 op: LikeOp::Like,
1393 escape: Some(_),
1394 ..
1395 }
1396 ));
1397 }
1398
1399 #[test]
1400 fn test_glob_pattern() {
1401 let expr = parse("path GLOB '*.rs'");
1402 assert!(matches!(
1403 expr,
1404 Expr::Like {
1405 op: LikeOp::Glob,
1406 not: false,
1407 ..
1408 }
1409 ));
1410 }
1411
1412 #[test]
1413 fn test_glob_character_class() {
1414 let expr = parse("name GLOB '[a-z]*'");
1415 match &expr {
1416 Expr::Like {
1417 op: LikeOp::Glob,
1418 pattern,
1419 ..
1420 } => assert!(matches!(
1421 pattern.as_ref(),
1422 Expr::Literal(Literal::String(s), _) if s == "[a-z]*"
1423 )),
1424 other => unreachable!("expected GLOB, got {other:?}"),
1425 }
1426 }
1427
1428 #[test]
1431 fn test_collate_override() {
1432 let expr = parse("name COLLATE NOCASE");
1433 match &expr {
1434 Expr::Collate { collation, .. } => {
1435 assert_eq!(collation, "NOCASE");
1436 }
1437 other => unreachable!("expected COLLATE, got {other:?}"),
1438 }
1439 }
1440
1441 #[test]
1444 fn test_json_arrow_operator() {
1445 let expr = parse("data -> 'key'");
1446 assert!(matches!(
1447 expr,
1448 Expr::JsonAccess {
1449 arrow: JsonArrow::Arrow,
1450 ..
1451 }
1452 ));
1453 }
1454
1455 #[test]
1456 fn test_json_double_arrow_operator() {
1457 let expr = parse("data ->> 'key'");
1458 assert!(matches!(
1459 expr,
1460 Expr::JsonAccess {
1461 arrow: JsonArrow::DoubleArrow,
1462 ..
1463 }
1464 ));
1465 }
1466
1467 #[test]
1470 fn test_is_null() {
1471 assert!(matches!(
1472 parse("42"),
1473 Expr::Literal(Literal::Integer(42), _)
1474 ));
1475 assert!(matches!(parse("3.14"), Expr::Literal(Literal::Float(_), _)));
1476 assert!(matches!(
1477 parse("'hello'"),
1478 Expr::Literal(Literal::String(_), _)
1479 ));
1480 assert!(matches!(parse("NULL"), Expr::Literal(Literal::Null, _)));
1481 assert!(matches!(parse("TRUE"), Expr::Literal(Literal::True, _)));
1482 assert!(matches!(parse("FALSE"), Expr::Literal(Literal::False, _)));
1483 }
1484
1485 #[test]
1486 fn test_placeholders() {
1487 assert!(matches!(
1488 parse("?"),
1489 Expr::Placeholder(PlaceholderType::Anonymous, _)
1490 ));
1491 assert!(matches!(
1492 parse("?1"),
1493 Expr::Placeholder(PlaceholderType::Numbered(1), _)
1494 ));
1495 assert!(matches!(
1496 parse(":name"),
1497 Expr::Placeholder(PlaceholderType::ColonNamed(_), _)
1498 ));
1499 }
1500
1501 #[test]
1504 fn test_column_bare() {
1505 match &parse("x") {
1506 Expr::Column(
1507 ColumnRef {
1508 table: None,
1509 column,
1510 },
1511 _,
1512 ) => assert_eq!(column.as_ref(), "x"),
1513 other => unreachable!("expected bare column, got {other:?}"),
1514 }
1515 }
1516
1517 #[test]
1518 fn test_column_qualified() {
1519 match &parse("t.x") {
1520 Expr::Column(
1521 ColumnRef {
1522 table: Some(t),
1523 column,
1524 },
1525 _,
1526 ) => {
1527 assert_eq!(t.as_ref(), "t");
1528 assert_eq!(column.as_ref(), "x");
1529 }
1530 other => unreachable!("expected qualified column, got {other:?}"),
1531 }
1532 }
1533
1534 #[test]
1537 fn test_concat_higher_than_add() {
1538 let expr = parse("a + b || c");
1540 match &expr {
1541 Expr::BinaryOp {
1542 op: BinaryOp::Add,
1543 right,
1544 ..
1545 } => assert!(matches!(
1546 right.as_ref(),
1547 Expr::BinaryOp {
1548 op: BinaryOp::Concat,
1549 ..
1550 }
1551 )),
1552 other => unreachable!("expected Add(a, Concat(b,c)), got {other:?}"),
1553 }
1554 }
1555
1556 #[test]
1559 fn test_parenthesized() {
1560 let expr = parse("(1 + 2) * 3");
1562 match &expr {
1563 Expr::BinaryOp {
1564 op: BinaryOp::Multiply,
1565 left,
1566 ..
1567 } => assert!(matches!(
1568 left.as_ref(),
1569 Expr::BinaryOp {
1570 op: BinaryOp::Add,
1571 ..
1572 }
1573 )),
1574 other => unreachable!("expected Mul(Add, 3), got {other:?}"),
1575 }
1576 }
1577
1578 #[test]
1581 fn test_is_operator() {
1582 assert!(matches!(
1583 parse("a IS b"),
1584 Expr::BinaryOp {
1585 op: BinaryOp::Is,
1586 ..
1587 }
1588 ));
1589 }
1590
1591 #[test]
1592 fn test_is_not_operator() {
1593 assert!(matches!(
1594 parse("a IS NOT b"),
1595 Expr::BinaryOp {
1596 op: BinaryOp::IsNot,
1597 ..
1598 }
1599 ));
1600 }
1601
1602 #[test]
1605 fn test_bitwise_ops() {
1606 let expr = parse("a & b | c");
1608 match &expr {
1609 Expr::BinaryOp {
1610 op: BinaryOp::BitOr,
1611 left,
1612 ..
1613 } => assert!(
1614 matches!(
1615 left.as_ref(),
1616 Expr::BinaryOp {
1617 op: BinaryOp::BitAnd,
1618 ..
1619 }
1620 ),
1621 "bitwise operators should be left-associative"
1622 ),
1623 other => unreachable!("expected BitOr(BitAnd, c), got {other:?}"),
1624 }
1625 }
1626
1627 #[test]
1628 fn test_bitnot() {
1629 assert!(matches!(
1630 parse("~x"),
1631 Expr::UnaryOp {
1632 op: UnaryOp::BitNot,
1633 ..
1634 }
1635 ));
1636 }
1637
1638 #[test]
1641 fn test_complex_where_clause() {
1642 let expr = parse("a > 1 AND b LIKE '%test%' OR NOT c IS NULL");
1643 assert!(matches!(
1644 expr,
1645 Expr::BinaryOp {
1646 op: BinaryOp::Or,
1647 ..
1648 }
1649 ));
1650 }
1651
1652 #[test]
1653 fn test_not_like_pattern() {
1654 assert!(matches!(
1655 parse("name NOT LIKE '%foo'"),
1656 Expr::Like {
1657 op: LikeOp::Like,
1658 not: true,
1659 ..
1660 }
1661 ));
1662 }
1663
1664 #[test]
1665 fn test_subquery_expr() {
1666 assert!(matches!(parse("(SELECT 1)"), Expr::Subquery(..)));
1667 }
1668
1669 #[test]
1677 fn test_pratt_level1_or_left_assoc() {
1678 let expr = parse("a OR b OR c");
1680 match &expr {
1681 Expr::BinaryOp {
1682 op: BinaryOp::Or,
1683 left,
1684 ..
1685 } => assert!(
1686 matches!(
1687 left.as_ref(),
1688 Expr::BinaryOp {
1689 op: BinaryOp::Or,
1690 ..
1691 }
1692 ),
1693 "OR should be left-associative"
1694 ),
1695 other => unreachable!("expected Or(Or(a,b), c), got {other:?}"),
1696 }
1697 }
1698
1699 #[test]
1701 fn test_pratt_level2_and_left_assoc() {
1702 let expr = parse("a AND b AND c");
1704 match &expr {
1705 Expr::BinaryOp {
1706 op: BinaryOp::And,
1707 left,
1708 ..
1709 } => assert!(
1710 matches!(
1711 left.as_ref(),
1712 Expr::BinaryOp {
1713 op: BinaryOp::And,
1714 ..
1715 }
1716 ),
1717 "AND should be left-associative"
1718 ),
1719 other => unreachable!("expected And(And(a,b), c), got {other:?}"),
1720 }
1721 }
1722
1723 #[test]
1725 fn test_pratt_level3_not_higher_than_and() {
1726 let expr = parse("NOT a AND b");
1728 match &expr {
1729 Expr::BinaryOp {
1730 op: BinaryOp::And,
1731 left,
1732 ..
1733 } => assert!(
1734 matches!(
1735 left.as_ref(),
1736 Expr::UnaryOp {
1737 op: UnaryOp::Not,
1738 ..
1739 }
1740 ),
1741 "NOT should bind tighter than AND"
1742 ),
1743 other => unreachable!("expected And(Not(a), b), got {other:?}"),
1744 }
1745 }
1746
1747 #[test]
1749 fn test_pratt_level4_equality_left_assoc() {
1750 let expr = parse("a = b != c");
1752 match &expr {
1753 Expr::BinaryOp {
1754 op: BinaryOp::Ne,
1755 left,
1756 ..
1757 } => assert!(
1758 matches!(
1759 left.as_ref(),
1760 Expr::BinaryOp {
1761 op: BinaryOp::Eq,
1762 ..
1763 }
1764 ),
1765 "equality operators should be left-associative at same level"
1766 ),
1767 other => unreachable!("expected Ne(Eq(a,b), c), got {other:?}"),
1768 }
1769 }
1770
1771 #[test]
1775 fn test_pratt_level4_vs_level5_eq_lt_boundary() {
1776 let expr = parse("a = b < c");
1779 match &expr {
1780 Expr::BinaryOp {
1781 op: BinaryOp::Eq,
1782 right,
1783 ..
1784 } => assert!(
1785 matches!(
1786 right.as_ref(),
1787 Expr::BinaryOp {
1788 op: BinaryOp::Lt,
1789 ..
1790 }
1791 ),
1792 "a = b < c MUST parse as a = (b < c): relational binds tighter"
1793 ),
1794 other => unreachable!("expected Eq(a, Lt(b,c)), got {other:?}"),
1795 }
1796 }
1797
1798 #[test]
1800 fn test_pratt_level4_vs_level5_ne_ge_boundary() {
1801 let expr = parse("a != b >= c");
1803 match &expr {
1804 Expr::BinaryOp {
1805 op: BinaryOp::Ne,
1806 right,
1807 ..
1808 } => assert!(
1809 matches!(
1810 right.as_ref(),
1811 Expr::BinaryOp {
1812 op: BinaryOp::Ge,
1813 ..
1814 }
1815 ),
1816 "a != b >= c must parse as a != (b >= c)"
1817 ),
1818 other => unreachable!("expected Ne(Ge(b,c)), got {other:?}"),
1819 }
1820 }
1821
1822 #[test]
1824 fn test_pratt_level5_relational_left_assoc() {
1825 let expr = parse("a < b >= c");
1827 match &expr {
1828 Expr::BinaryOp {
1829 op: BinaryOp::Ge,
1830 left,
1831 ..
1832 } => assert!(
1833 matches!(
1834 left.as_ref(),
1835 Expr::BinaryOp {
1836 op: BinaryOp::Lt,
1837 ..
1838 }
1839 ),
1840 "relational operators should be left-associative"
1841 ),
1842 other => unreachable!("expected Ge(Lt(a,b), c), got {other:?}"),
1843 }
1844 }
1845
1846 #[test]
1848 fn test_pratt_level6_bitwise_tighter_than_comparison() {
1849 let expr = parse("a < b & c");
1851 match &expr {
1852 Expr::BinaryOp {
1853 op: BinaryOp::Lt,
1854 right,
1855 ..
1856 } => assert!(
1857 matches!(
1858 right.as_ref(),
1859 Expr::BinaryOp {
1860 op: BinaryOp::BitAnd,
1861 ..
1862 }
1863 ),
1864 "bitwise should bind tighter than relational"
1865 ),
1866 other => unreachable!("expected Lt(a, BitAnd(b,c)), got {other:?}"),
1867 }
1868 }
1869
1870 #[test]
1872 fn test_pratt_level6_shifts_left_assoc() {
1873 let expr = parse("a << b >> c");
1875 match &expr {
1876 Expr::BinaryOp {
1877 op: BinaryOp::ShiftRight,
1878 left,
1879 ..
1880 } => assert!(
1881 matches!(
1882 left.as_ref(),
1883 Expr::BinaryOp {
1884 op: BinaryOp::ShiftLeft,
1885 ..
1886 }
1887 ),
1888 "shift operators should be left-associative"
1889 ),
1890 other => unreachable!("expected ShiftRight(ShiftLeft(a,b), c), got {other:?}"),
1891 }
1892 }
1893
1894 #[test]
1896 fn test_pratt_level7_add_sub_left_assoc() {
1897 let expr = parse("a + b - c");
1899 match &expr {
1900 Expr::BinaryOp {
1901 op: BinaryOp::Subtract,
1902 left,
1903 ..
1904 } => assert!(
1905 matches!(
1906 left.as_ref(),
1907 Expr::BinaryOp {
1908 op: BinaryOp::Add,
1909 ..
1910 }
1911 ),
1912 "add/sub should be left-associative"
1913 ),
1914 other => unreachable!("expected Sub(Add(a,b), c), got {other:?}"),
1915 }
1916 }
1917
1918 #[test]
1919 fn test_pratt_level7_add_sub_left_assoc_reverse() {
1920 let expr = parse("a - b + c");
1922 match &expr {
1923 Expr::BinaryOp {
1924 op: BinaryOp::Add,
1925 left,
1926 ..
1927 } => assert!(
1928 matches!(
1929 left.as_ref(),
1930 Expr::BinaryOp {
1931 op: BinaryOp::Subtract,
1932 ..
1933 }
1934 ),
1935 "add/sub should be left-associative"
1936 ),
1937 other => unreachable!("expected Add(Sub(a,b), c), got {other:?}"),
1938 }
1939 }
1940
1941 #[test]
1942 fn test_pratt_level9_concat_tighter_than_mul() {
1943 let expr = parse("a * b || c");
1945 match &expr {
1946 Expr::BinaryOp {
1947 op: BinaryOp::Multiply,
1948 right,
1949 ..
1950 } => assert!(
1951 matches!(
1952 right.as_ref(),
1953 Expr::BinaryOp {
1954 op: BinaryOp::Concat,
1955 ..
1956 }
1957 ),
1958 "concat should bind tighter than multiply"
1959 ),
1960 other => unreachable!("expected Mul(a, Concat(b,c)), got {other:?}"),
1961 }
1962 }
1963
1964 #[test]
1966 fn test_pratt_level8_mul_div_left_assoc() {
1967 let expr = parse("a * b / c");
1969 match &expr {
1970 Expr::BinaryOp {
1971 op: BinaryOp::Divide,
1972 left,
1973 ..
1974 } => assert!(
1975 matches!(
1976 left.as_ref(),
1977 Expr::BinaryOp {
1978 op: BinaryOp::Multiply,
1979 ..
1980 }
1981 ),
1982 "mul/div should be left-associative"
1983 ),
1984 other => unreachable!("expected Div(Mul(a,b), c), got {other:?}"),
1985 }
1986 }
1987
1988 #[test]
1989 fn test_pratt_level8_modulo() {
1990 let expr = parse("a * b % c");
1992 match &expr {
1993 Expr::BinaryOp {
1994 op: BinaryOp::Modulo,
1995 left,
1996 ..
1997 } => assert!(
1998 matches!(
1999 left.as_ref(),
2000 Expr::BinaryOp {
2001 op: BinaryOp::Multiply,
2002 ..
2003 }
2004 ),
2005 "modulo and multiply at same level, left-associative"
2006 ),
2007 other => unreachable!("expected Mod(Mul(a,b), c), got {other:?}"),
2008 }
2009 }
2010
2011 #[test]
2013 fn test_pratt_level9_concat_left_assoc() {
2014 let expr = parse("a || b || c");
2016 match &expr {
2017 Expr::BinaryOp {
2018 op: BinaryOp::Concat,
2019 left,
2020 ..
2021 } => assert!(
2022 matches!(
2023 left.as_ref(),
2024 Expr::BinaryOp {
2025 op: BinaryOp::Concat,
2026 ..
2027 }
2028 ),
2029 "concatenation should be left-associative"
2030 ),
2031 other => unreachable!("expected Concat(Concat(a,b), c), got {other:?}"),
2032 }
2033 }
2034
2035 #[test]
2036 fn test_pratt_level9_concat_left_assoc_reverse() {
2037 let expr = parse("a || b || c");
2039 match &expr {
2040 Expr::BinaryOp {
2041 op: BinaryOp::Concat,
2042 left,
2043 ..
2044 } => assert!(
2045 matches!(
2046 left.as_ref(),
2047 Expr::BinaryOp {
2048 op: BinaryOp::Concat,
2049 ..
2050 }
2051 ),
2052 "concatenation should be left-associative"
2053 ),
2054 other => unreachable!("expected Concat(Concat(a,b), c), got {other:?}"),
2055 }
2056 }
2057
2058 #[test]
2060 fn test_pratt_level10_collate_tighter_than_concat() {
2061 let expr = parse("a || b COLLATE NOCASE");
2063 match &expr {
2064 Expr::BinaryOp {
2065 op: BinaryOp::Concat,
2066 right,
2067 ..
2068 } => assert!(
2069 matches!(right.as_ref(), Expr::Collate { .. }),
2070 "COLLATE should bind tighter than concat"
2071 ),
2072 other => unreachable!("expected Concat(a, Collate(b)), got {other:?}"),
2073 }
2074 }
2075
2076 #[test]
2078 fn test_pratt_level11_unary_negate_tightest() {
2079 let expr = parse("-a * b");
2081 match &expr {
2082 Expr::BinaryOp {
2083 op: BinaryOp::Multiply,
2084 left,
2085 ..
2086 } => assert!(
2087 matches!(
2088 left.as_ref(),
2089 Expr::UnaryOp {
2090 op: UnaryOp::Negate,
2091 ..
2092 }
2093 ),
2094 "unary minus should bind tighter than multiply"
2095 ),
2096 other => unreachable!("expected Mul(Negate(a), b), got {other:?}"),
2097 }
2098 }
2099
2100 #[test]
2101 fn test_pratt_level11_bitnot_tightest() {
2102 let expr = parse("~a + b");
2104 match &expr {
2105 Expr::BinaryOp {
2106 op: BinaryOp::Add,
2107 left,
2108 ..
2109 } => assert!(
2110 matches!(
2111 left.as_ref(),
2112 Expr::UnaryOp {
2113 op: UnaryOp::BitNot,
2114 ..
2115 }
2116 ),
2117 "bitwise NOT should bind tighter than addition"
2118 ),
2119 other => unreachable!("expected Add(BitNot(a), b), got {other:?}"),
2120 }
2121 }
2122
2123 #[test]
2125 fn test_pratt_escape_not_infix_operator() {
2126 let expr = parse("a LIKE b ESCAPE c");
2128 match &expr {
2129 Expr::Like {
2130 escape: Some(esc), ..
2131 } => assert!(
2132 matches!(esc.as_ref(), Expr::Column(_, _)),
2133 "ESCAPE should be parsed as suffix of LIKE, not standalone infix"
2134 ),
2135 other => unreachable!("expected Like with escape, got {other:?}"),
2136 }
2137 }
2138
2139 #[test]
2140 fn test_pratt_escape_glob_not_infix() {
2141 let expr = parse("a GLOB b ESCAPE c");
2143 match &expr {
2144 Expr::Like {
2145 op: LikeOp::Glob,
2146 escape: Some(_),
2147 ..
2148 } => {}
2149 other => unreachable!("expected Glob with escape, got {other:?}"),
2150 }
2151 }
2152
2153 #[test]
2155 fn test_pratt_error_recovery_multiple_errors() {
2156 use crate::parser::Parser;
2157 let mut p = Parser::from_sql("SELECT +; SELECT *; SELECT 1");
2158 let (stmts, errs) = p.parse_all();
2159 assert!(
2162 !stmts.is_empty(),
2163 "should recover and parse at least one valid statement"
2164 );
2165 assert!(
2166 !errs.is_empty(),
2167 "should collect at least one error from malformed statements"
2168 );
2169 }
2170
2171 #[test]
2173 fn test_pratt_complex_mixed_all_levels() {
2174 let expr = parse("NOT a = b + c * -d OR e < f AND g LIKE h");
2177 match &expr {
2179 Expr::BinaryOp {
2180 op: BinaryOp::Or,
2181 left,
2182 right,
2183 ..
2184 } => {
2185 assert!(
2187 matches!(
2188 left.as_ref(),
2189 Expr::UnaryOp {
2190 op: UnaryOp::Not,
2191 ..
2192 }
2193 ),
2194 "left of OR should be NOT(...)"
2195 );
2196 match right.as_ref() {
2198 Expr::BinaryOp {
2199 op: BinaryOp::And,
2200 left: and_left,
2201 right: and_right,
2202 ..
2203 } => {
2204 assert!(
2205 matches!(
2206 and_left.as_ref(),
2207 Expr::BinaryOp {
2208 op: BinaryOp::Lt,
2209 ..
2210 }
2211 ),
2212 "left of AND should be Lt(e,f)"
2213 );
2214 assert!(
2215 matches!(and_right.as_ref(), Expr::Like { .. }),
2216 "right of AND should be Like(g,h)"
2217 );
2218 }
2219 other => unreachable!("expected And(Lt, Like), got {other:?}"),
2220 }
2221
2222 if let Expr::UnaryOp {
2225 expr: not_inner, ..
2226 } = left.as_ref()
2227 {
2228 if let Expr::BinaryOp {
2229 op: BinaryOp::Eq,
2230 right: eq_right,
2231 ..
2232 } = not_inner.as_ref()
2233 {
2234 if let Expr::BinaryOp {
2235 op: BinaryOp::Add,
2236 right: add_right,
2237 ..
2238 } = eq_right.as_ref()
2239 {
2240 if let Expr::BinaryOp {
2241 op: BinaryOp::Multiply,
2242 right: mul_right,
2243 ..
2244 } = add_right.as_ref()
2245 {
2246 assert!(
2247 matches!(
2248 mul_right.as_ref(),
2249 Expr::UnaryOp {
2250 op: UnaryOp::Negate,
2251 ..
2252 }
2253 ),
2254 "deepest: negate"
2255 );
2256 } else {
2257 unreachable!("expected Mul in add_right");
2258 }
2259 } else {
2260 unreachable!("expected Add in eq_right");
2261 }
2262 } else {
2263 unreachable!("expected Eq inside NOT");
2264 }
2265 }
2266 }
2267 other => unreachable!("expected Or(Not(...), And(...)), got {other:?}"),
2268 }
2269 }
2270
2271 #[test]
2273 fn test_pratt_json_same_precedence_as_concat() {
2274 let expr = parse("a || b -> c");
2276 match &expr {
2277 Expr::JsonAccess {
2278 expr: left,
2279 path: right,
2280 arrow: JsonArrow::Arrow,
2281 ..
2282 } => {
2283 assert!(
2284 matches!(
2285 left.as_ref(),
2286 Expr::BinaryOp {
2287 op: BinaryOp::Concat,
2288 ..
2289 }
2290 ),
2291 "left side should be concat expression"
2292 );
2293 assert!(
2294 matches!(right.as_ref(), Expr::Column(_, _)),
2295 "path should remain the right-hand expression"
2296 );
2297 }
2298 other => unreachable!("expected JsonAccess(Concat(a,b), c), got {other:?}"),
2299 }
2300 }
2301
2302 #[test]
2303 fn test_pratt_double_arrow_same_precedence_as_concat() {
2304 let expr = parse("a || b ->> c");
2305 assert!(
2306 matches!(
2307 expr,
2308 Expr::JsonAccess {
2309 arrow: JsonArrow::DoubleArrow,
2310 ..
2311 }
2312 ),
2313 "double-arrow should parse as JsonAccess at the same precedence level as concat"
2314 );
2315 }
2316}