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