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 if matches!(self.peek_kind(), TokenKind::KwNull) {
565 let end = self.advance_token().span;
566 let span = lhs.span().merge(end);
567 return Ok(Expr::IsNull {
568 expr: Box::new(lhs),
569 not,
570 span,
571 });
572 }
573 let rhs = self.parse_expr_bp(r_bp)?;
574 let span = lhs.span().merge(rhs.span());
575 let op = if not { BinaryOp::IsNot } else { BinaryOp::Is };
576 Ok(Expr::BinaryOp {
577 left: Box::new(lhs),
578 op,
579 right: Box::new(rhs),
580 span,
581 })
582 }
583
584 TokenKind::KwLike => self.parse_like(lhs, LikeOp::Like, false),
586 TokenKind::KwGlob => self.parse_like(lhs, LikeOp::Glob, false),
587 TokenKind::KwMatch => self.parse_like(lhs, LikeOp::Match, false),
588 TokenKind::KwRegexp => self.parse_like(lhs, LikeOp::Regexp, false),
589
590 TokenKind::KwBetween => self.parse_between(lhs, false),
592
593 TokenKind::KwIn => self.parse_in(lhs, false),
595
596 TokenKind::Arrow => {
598 let rhs = self.parse_expr_bp(r_bp)?;
599 let span = lhs.span().merge(rhs.span());
600 Ok(Expr::JsonAccess {
601 expr: Box::new(lhs),
602 path: Box::new(rhs),
603 arrow: JsonArrow::Arrow,
604 span,
605 })
606 }
607 TokenKind::DoubleArrow => {
608 let rhs = self.parse_expr_bp(r_bp)?;
609 let span = lhs.span().merge(rhs.span());
610 Ok(Expr::JsonAccess {
611 expr: Box::new(lhs),
612 path: Box::new(rhs),
613 arrow: JsonArrow::DoubleArrow,
614 span,
615 })
616 }
617
618 TokenKind::KwNot => {
620 let next = self.advance_token();
621 match &next.kind {
622 TokenKind::KwLike => self.parse_like(lhs, LikeOp::Like, true),
623 TokenKind::KwGlob => self.parse_like(lhs, LikeOp::Glob, true),
624 TokenKind::KwMatch => self.parse_like(lhs, LikeOp::Match, true),
625 TokenKind::KwRegexp => self.parse_like(lhs, LikeOp::Regexp, true),
626 TokenKind::KwBetween => self.parse_between(lhs, true),
627 TokenKind::KwIn => self.parse_in(lhs, true),
628 _ => Err(ParseError::at(
629 format!(
630 "expected LIKE/GLOB/MATCH/REGEXP/BETWEEN/IN \
631 after NOT, got {:?}",
632 next.kind
633 ),
634 Some(&next),
635 )),
636 }
637 }
638
639 other => Err(ParseError::at(
640 format!("unexpected infix token: {other:?}"),
641 Some(&tok),
642 )),
643 }
644 }
645
646 fn make_binop(&mut self, lhs: Expr, op: BinaryOp, r_bp: u8) -> Result<Expr, ParseError> {
647 let rhs = self.parse_expr_bp(r_bp)?;
648 let span = lhs.span().merge(rhs.span());
649 Ok(Expr::BinaryOp {
650 left: Box::new(lhs),
651 op,
652 right: Box::new(rhs),
653 span,
654 })
655 }
656
657 fn parse_like(&mut self, lhs: Expr, op: LikeOp, not: bool) -> Result<Expr, ParseError> {
660 let pattern = self.parse_expr_bp(bp::EQUALITY.1)?;
661 let escape = if self.eat_kind(&TokenKind::KwEscape) {
662 Some(Box::new(self.parse_expr_bp(bp::EQUALITY.1)?))
665 } else {
666 None
667 };
668 let end = escape.as_ref().map_or_else(|| pattern.span(), |e| e.span());
669 let span = lhs.span().merge(end);
670 Ok(Expr::Like {
671 expr: Box::new(lhs),
672 pattern: Box::new(pattern),
673 escape,
674 op,
675 not,
676 span,
677 })
678 }
679
680 fn parse_between(&mut self, lhs: Expr, not: bool) -> Result<Expr, ParseError> {
681 let low = self.parse_expr_bp(bp::NOT_PREFIX)?;
683 if !self.eat_kind(&TokenKind::KwAnd) {
684 return Err(self.err_here("expected AND in BETWEEN expression"));
685 }
686 let high = self.parse_expr_bp(bp::EQUALITY.1)?;
687 let span = lhs.span().merge(high.span());
688 Ok(Expr::Between {
689 expr: Box::new(lhs),
690 low: Box::new(low),
691 high: Box::new(high),
692 not,
693 span,
694 })
695 }
696
697 fn parse_in(&mut self, lhs: Expr, not: bool) -> Result<Expr, ParseError> {
698 let start = lhs.span();
699
700 if !self.at_kind(&TokenKind::LeftParen) {
702 let table = self.parse_qualified_name()?;
703 let end = self.tokens[self.pos.saturating_sub(1)].span;
704 let span = start.merge(end);
705 return Ok(Expr::In {
706 expr: Box::new(lhs),
707 set: InSet::Table(table),
708 not,
709 span,
710 });
711 }
712
713 self.expect_kind(&TokenKind::LeftParen)?;
714
715 if matches!(
716 self.peek_kind(),
717 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
718 ) {
719 let subquery = self.parse_subquery_minimal()?;
720 let end = self.expect_kind(&TokenKind::RightParen)?;
721 let span = start.merge(end);
722 return Ok(Expr::In {
723 expr: Box::new(lhs),
724 set: InSet::Subquery(Box::new(subquery)),
725 not,
726 span,
727 });
728 }
729
730 let mut exprs = Vec::new();
731 if !self.at_kind(&TokenKind::RightParen) {
732 exprs.push(self.parse_expr()?);
733 while self.eat_kind(&TokenKind::Comma) {
734 exprs.push(self.parse_expr()?);
735 }
736 }
737 let end = self.expect_kind(&TokenKind::RightParen)?;
738 let span = start.merge(end);
739 Ok(Expr::In {
740 expr: Box::new(lhs),
741 set: InSet::List(exprs),
742 not,
743 span,
744 })
745 }
746
747 fn parse_case_expr(&mut self, start: Span) -> Result<Expr, ParseError> {
748 let operand = if matches!(self.peek_kind(), TokenKind::KwWhen) {
749 None
750 } else {
751 Some(Box::new(self.parse_expr()?))
752 };
753
754 let mut whens = Vec::new();
755 while self.eat_kind(&TokenKind::KwWhen) {
756 let condition = self.parse_expr()?;
757 if !self.eat_kind(&TokenKind::KwThen) {
758 return Err(self.err_here("expected THEN in CASE expression"));
759 }
760 let result = self.parse_expr()?;
761 whens.push((condition, result));
762 }
763 if whens.is_empty() {
764 return Err(self.err_here("CASE requires at least one WHEN clause"));
765 }
766
767 let else_expr = if self.eat_kind(&TokenKind::KwElse) {
768 Some(Box::new(self.parse_expr()?))
769 } else {
770 None
771 };
772
773 if !self.eat_kind(&TokenKind::KwEnd) {
774 return Err(self.err_here("expected END for CASE expression"));
775 }
776 let end = self.tokens[self.pos.saturating_sub(1)].span;
777 let span = start.merge(end);
778 Ok(Expr::Case {
779 operand,
780 whens,
781 else_expr,
782 span,
783 })
784 }
785
786 fn parse_function_call(&mut self, name: String, start: Span) -> Result<Expr, ParseError> {
787 self.expect_kind(&TokenKind::LeftParen)?;
788
789 let (args, distinct) = if matches!(self.peek_kind(), TokenKind::Star) {
790 if !name.eq_ignore_ascii_case("count") {
791 return Err(self.err_here("'*' can only be used with count() function"));
792 }
793 self.advance_token();
794 (FunctionArgs::Star, false)
795 } else {
796 let distinct = self.eat_kind(&TokenKind::KwDistinct);
797 let args = if matches!(self.peek_kind(), TokenKind::RightParen) {
798 if distinct {
799 return Err(self.err_here("DISTINCT requires at least one argument"));
800 }
801 FunctionArgs::List(Vec::new())
802 } else {
803 let mut list = vec![self.parse_expr()?];
804 while self.eat_kind(&TokenKind::Comma) {
805 list.push(self.parse_expr()?);
806 }
807 FunctionArgs::List(list)
808 };
809 (args, distinct)
810 };
811
812 let order_by = if self.eat_kind(&TokenKind::KwOrder) {
814 self.expect_kind(&TokenKind::KwBy)?;
815 self.parse_comma_sep(Self::parse_ordering_term)?
816 } else {
817 vec![]
818 };
819
820 let mut end = self.expect_kind(&TokenKind::RightParen)?;
821 let filter = if matches!(self.peek_kind(), TokenKind::KwFilter)
824 && self
825 .tokens
826 .get(self.pos + 1)
827 .is_some_and(|t| t.kind == TokenKind::LeftParen)
828 {
829 self.advance_token(); self.expect_kind(&TokenKind::LeftParen)?;
831 self.expect_kind(&TokenKind::KwWhere)?;
832 let predicate = self.parse_expr()?;
833 let filter_end = self.expect_kind(&TokenKind::RightParen)?;
834 end = end.merge(filter_end);
835 Some(Box::new(predicate))
836 } else {
837 None
838 };
839 let over = if matches!(self.peek_kind(), TokenKind::KwOver)
842 && self.tokens.get(self.pos + 1).is_some_and(|t| {
843 matches!(
844 t.kind,
845 TokenKind::LeftParen | TokenKind::Id(_) | TokenKind::QuotedId(_, _)
846 )
847 }) {
848 self.advance_token(); if self.eat_kind(&TokenKind::LeftParen) {
850 let spec = self.parse_window_spec()?;
851 let over_end = self.expect_kind(&TokenKind::RightParen)?;
852 end = end.merge(over_end);
853 Some(spec)
854 } else {
855 let base_window = self.parse_identifier()?;
856 let base_span = self.tokens[self.pos.saturating_sub(1)].span;
857 end = end.merge(base_span);
858 Some(WindowSpec {
859 base_window: Some(base_window),
860 partition_by: Vec::new(),
861 order_by: Vec::new(),
862 frame: None,
863 })
864 }
865 } else {
866 None
867 };
868
869 let span = start.merge(end);
870 Ok(Expr::FunctionCall {
871 name,
872 args,
873 distinct,
874 order_by,
875 filter,
876 over,
877 span,
878 })
879 }
880
881 fn parse_raise_args(&mut self) -> Result<(RaiseAction, Option<String>), ParseError> {
882 let action_tok = self.advance_token();
883 let action = match &action_tok.kind {
884 TokenKind::KwIgnore => RaiseAction::Ignore,
885 TokenKind::KwRollback => RaiseAction::Rollback,
886 TokenKind::KwAbort => RaiseAction::Abort,
887 TokenKind::KwFail => RaiseAction::Fail,
888 _ => {
889 return Err(ParseError::at(
890 "expected IGNORE, ROLLBACK, ABORT, or FAIL in RAISE",
891 Some(&action_tok),
892 ));
893 }
894 };
895 if matches!(action, RaiseAction::Ignore) {
896 return Ok((action, None));
897 }
898 self.expect_kind(&TokenKind::Comma)?;
899 let msg_tok = self.advance_token();
900 let message = match &msg_tok.kind {
901 TokenKind::String(s) => s.clone(),
902 _ => {
903 return Err(ParseError::at(
904 "expected string message in RAISE",
905 Some(&msg_tok),
906 ));
907 }
908 };
909 Ok((action, Some(message)))
910 }
911
912 fn parse_type_name(&mut self) -> Result<TypeName, ParseError> {
913 let mut parts = Vec::new();
914 loop {
915 match self.peek_kind() {
916 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
917 let tok = self.advance_token();
918 if let TokenKind::Id(s) | TokenKind::QuotedId(s, _) = &tok.kind {
919 parts.push(s.to_string());
920 } else {
921 unreachable!();
922 }
923 }
924 k if is_nonreserved_kw(k) => {
925 let tok = self.advance_token();
926 parts.push(kw_to_str(&tok.kind));
927 }
928 _ => break,
929 }
930 }
931 if parts.is_empty() {
932 return Err(self.err_here("expected type name"));
933 }
934 let name = parts.join(" ");
935
936 let (arg1, arg2) = if self.eat_kind(&TokenKind::LeftParen) {
937 let a1 = self.parse_type_arg()?;
938 let a2 = if self.eat_kind(&TokenKind::Comma) {
939 Some(self.parse_type_arg()?)
940 } else {
941 None
942 };
943 self.expect_kind(&TokenKind::RightParen)?;
944 (Some(a1), a2)
945 } else {
946 (None, None)
947 };
948
949 Ok(TypeName { name, arg1, arg2 })
950 }
951
952 fn parse_type_arg(&mut self) -> Result<String, ParseError> {
953 let tok = self.advance_token();
954 match &tok.kind {
955 TokenKind::Integer(i) => Ok(i.to_string()),
956 TokenKind::Float(f) => Ok(f.to_string()),
957 TokenKind::Minus => {
958 let next = self.advance_token();
959 match &next.kind {
960 TokenKind::Integer(i) => Ok(format!("-{i}")),
961 TokenKind::OversizedInt(s) => Ok(format!("-{s}")),
962 TokenKind::Float(f) => Ok(format!("-{f}")),
963 _ => Err(ParseError::at(
964 "expected number in type argument",
965 Some(&next),
966 )),
967 }
968 }
969 TokenKind::Plus => {
970 let next = self.advance_token();
971 match &next.kind {
972 TokenKind::Integer(i) => Ok(format!("+{i}")),
973 TokenKind::OversizedInt(s) => Ok(format!("+{s}")),
974 TokenKind::Float(f) => Ok(format!("+{f}")),
975 _ => Err(ParseError::at(
976 "expected number in type argument",
977 Some(&next),
978 )),
979 }
980 }
981 TokenKind::OversizedInt(s) => Ok(s.clone()),
982 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => Ok(s.to_string()),
983 _ => Err(ParseError::at("expected type argument", Some(&tok))),
984 }
985 }
986
987 fn parse_subquery_minimal(&mut self) -> Result<SelectStatement, ParseError> {
989 let with = if self.at_kind(&TokenKind::KwWith) {
990 Some(self.parse_with_clause()?)
991 } else {
992 None
993 };
994 self.parse_select_stmt(with)
995 }
996}
997
998pub fn parse_expr(sql: &str) -> Result<Expr, ParseError> {
1000 let mut parser = Parser::from_sql(sql);
1001 let expr = parser.parse_expr()?;
1002 if !matches!(parser.peek_kind(), TokenKind::Eof | TokenKind::Semicolon) {
1003 return Err(parser.err_here(format!(
1004 "unexpected token after expression: {:?}",
1005 parser.peek_kind()
1006 )));
1007 }
1008 Ok(expr)
1009}
1010
1011#[cfg(test)]
1012mod tests {
1013 use super::*;
1014 use fsqlite_ast::{SelectCore, TableOrSubquery};
1015
1016 fn parse(sql: &str) -> Expr {
1017 match parse_expr(sql) {
1018 Ok(expr) => expr,
1019 Err(err) => unreachable!("parse error for `{sql}`: {err}"),
1020 }
1021 }
1022
1023 #[test]
1026 fn test_not_lower_precedence_than_comparison() {
1027 let expr = parse("NOT x = y");
1029 match &expr {
1030 Expr::UnaryOp {
1031 op: UnaryOp::Not,
1032 expr: inner,
1033 ..
1034 } => match inner.as_ref() {
1035 Expr::BinaryOp {
1036 op: BinaryOp::Eq, ..
1037 } => {}
1038 other => unreachable!("expected Eq inside NOT, got {other:?}"),
1039 },
1040 other => unreachable!("expected NOT(Eq), got {other:?}"),
1041 }
1042 }
1043
1044 #[test]
1045 fn test_unary_binds_tighter_than_collate() {
1046 let expr = parse("-x COLLATE NOCASE");
1048 match &expr {
1049 Expr::Collate {
1050 expr: inner,
1051 collation,
1052 ..
1053 } => {
1054 assert_eq!(collation, "NOCASE");
1055 assert!(matches!(
1056 inner.as_ref(),
1057 Expr::UnaryOp {
1058 op: UnaryOp::Negate,
1059 ..
1060 }
1061 ));
1062 }
1063 other => unreachable!("expected COLLATE(Negate), got {other:?}"),
1064 }
1065 }
1066
1067 #[test]
1068 fn test_arithmetic_precedence() {
1069 let expr = parse("1 + 2 * 3");
1071 match &expr {
1072 Expr::BinaryOp {
1073 op: BinaryOp::Add,
1074 left,
1075 right,
1076 ..
1077 } => {
1078 assert!(matches!(
1079 left.as_ref(),
1080 Expr::Literal(Literal::Integer(1), _)
1081 ));
1082 assert!(matches!(
1083 right.as_ref(),
1084 Expr::BinaryOp {
1085 op: BinaryOp::Multiply,
1086 ..
1087 }
1088 ));
1089 }
1090 other => unreachable!("expected Add(1, Mul(2,3)), got {other:?}"),
1091 }
1092 }
1093
1094 #[test]
1095 fn test_and_higher_than_or() {
1096 let expr = parse("a OR b AND c");
1098 match &expr {
1099 Expr::BinaryOp {
1100 op: BinaryOp::Or,
1101 right,
1102 ..
1103 } => {
1104 assert!(matches!(
1105 right.as_ref(),
1106 Expr::BinaryOp {
1107 op: BinaryOp::And,
1108 ..
1109 }
1110 ));
1111 }
1112 other => unreachable!("expected Or(a, And(b,c)), got {other:?}"),
1113 }
1114 }
1115
1116 #[test]
1119 fn test_cast_expression() {
1120 let expr = parse("CAST(42 AS INTEGER)");
1121 match &expr {
1122 Expr::Cast {
1123 expr: inner,
1124 type_name,
1125 ..
1126 } => {
1127 assert!(matches!(
1128 inner.as_ref(),
1129 Expr::Literal(Literal::Integer(42), _)
1130 ));
1131 assert_eq!(type_name.name, "INTEGER");
1132 }
1133 other => unreachable!("expected Cast, got {other:?}"),
1134 }
1135 }
1136
1137 #[test]
1138 fn test_cast_float_argument() {
1139 let expr = parse("CAST(x AS DECIMAL(10.5, -2.5))");
1141 match &expr {
1142 Expr::Cast { type_name, .. } => {
1143 assert_eq!(type_name.name, "DECIMAL");
1144 assert_eq!(type_name.arg1.as_deref(), Some("10.5"));
1145 assert_eq!(type_name.arg2.as_deref(), Some("-2.5"));
1146 }
1147 other => unreachable!("expected Cast with float args, got {other:?}"),
1148 }
1149 }
1150
1151 #[test]
1152 fn test_cast_signed_args() {
1153 let expr = parse("CAST(x AS NUMERIC(+5, -5))");
1155 match &expr {
1156 Expr::Cast { type_name, .. } => {
1157 assert_eq!(type_name.name, "NUMERIC");
1158 assert_eq!(type_name.arg1.as_deref(), Some("+5"));
1159 assert_eq!(type_name.arg2.as_deref(), Some("-5"));
1160 }
1161 other => unreachable!("expected Cast with signed args, got {other:?}"),
1162 }
1163 }
1164
1165 #[test]
1168 fn test_case_when_simple() {
1169 let expr = parse(
1170 "CASE x WHEN 1 THEN 'one' WHEN 2 THEN 'two' \
1171 ELSE 'other' END",
1172 );
1173 match &expr {
1174 Expr::Case {
1175 operand: Some(op),
1176 whens,
1177 else_expr: Some(_),
1178 ..
1179 } => {
1180 assert!(matches!(op.as_ref(), Expr::Column(..)));
1181 assert_eq!(whens.len(), 2);
1182 }
1183 other => unreachable!("expected simple CASE, got {other:?}"),
1184 }
1185 }
1186
1187 #[test]
1188 fn test_case_when_searched() {
1189 let expr = parse(
1190 "CASE WHEN x > 0 THEN 'pos' WHEN x < 0 THEN 'neg' \
1191 ELSE 'zero' END",
1192 );
1193 match &expr {
1194 Expr::Case {
1195 operand: None,
1196 whens,
1197 else_expr: Some(_),
1198 ..
1199 } => {
1200 assert_eq!(whens.len(), 2);
1201 assert!(matches!(
1202 &whens[0].0,
1203 Expr::BinaryOp {
1204 op: BinaryOp::Gt,
1205 ..
1206 }
1207 ));
1208 }
1209 other => unreachable!("expected searched CASE, got {other:?}"),
1210 }
1211 }
1212
1213 #[test]
1216 fn test_exists_subquery() {
1217 let expr = parse("EXISTS (SELECT 1)");
1218 assert!(matches!(expr, Expr::Exists { not: false, .. }));
1219 }
1220
1221 #[test]
1222 fn test_not_exists_subquery() {
1223 let expr = parse("NOT EXISTS (SELECT 1)");
1224 assert!(matches!(expr, Expr::Exists { not: true, .. }));
1225 }
1226
1227 #[test]
1228 fn test_exists_subquery_supports_qualified_table_with_alias() {
1229 let expr = parse("EXISTS (SELECT 1 FROM main.users AS u WHERE u.id = 1)");
1230 match expr {
1231 Expr::Exists { subquery, .. } => match subquery.body.select {
1232 SelectCore::Select {
1233 from: Some(from), ..
1234 } => match from.source {
1235 TableOrSubquery::Table { name, alias, .. } => {
1236 assert_eq!(name.schema.as_deref(), Some("main"));
1237 assert_eq!(name.name, "users");
1238 assert_eq!(alias.as_deref(), Some("u"));
1239 }
1240 other => unreachable!("expected table source, got {other:?}"),
1241 },
1242 other => unreachable!("expected SELECT core with FROM, got {other:?}"),
1243 },
1244 other => unreachable!("expected EXISTS subquery, got {other:?}"),
1245 }
1246 }
1247
1248 #[test]
1251 fn test_in_expr_list() {
1252 let expr = parse("x IN (1, 2, 3)");
1253 match &expr {
1254 Expr::In {
1255 not: false,
1256 set: InSet::List(items),
1257 ..
1258 } => assert_eq!(items.len(), 3),
1259 other => unreachable!("expected IN list, got {other:?}"),
1260 }
1261 }
1262
1263 #[test]
1264 fn test_in_subquery() {
1265 let expr = parse("x IN (SELECT y FROM t)");
1266 assert!(matches!(
1267 expr,
1268 Expr::In {
1269 not: false,
1270 set: InSet::Subquery(_),
1271 ..
1272 }
1273 ));
1274 }
1275
1276 #[test]
1277 fn test_in_subquery_with_order_by_and_limit() {
1278 let expr =
1280 parse("id NOT IN (SELECT id FROM search_recipes ORDER BY updated_ts DESC LIMIT 5)");
1281 match &expr {
1282 Expr::In {
1283 not: true,
1284 set: InSet::Subquery(stmt),
1285 ..
1286 } => {
1287 assert_eq!(stmt.order_by.len(), 1, "ORDER BY should be parsed");
1288 assert!(stmt.limit.is_some(), "LIMIT should be parsed");
1289 }
1290 other => unreachable!("expected NOT IN subquery, got {other:?}"),
1291 }
1292 }
1293
1294 #[test]
1295 fn test_in_subquery_supports_group_by_and_having() {
1296 let expr = parse("x IN (SELECT y FROM t GROUP BY y HAVING COUNT(*) > 1)");
1297 match expr {
1298 Expr::In {
1299 set: InSet::Subquery(stmt),
1300 ..
1301 } => match stmt.body.select {
1302 SelectCore::Select {
1303 group_by, having, ..
1304 } => {
1305 assert_eq!(group_by.len(), 1, "GROUP BY should be parsed");
1306 assert!(having.is_some(), "HAVING should be parsed");
1307 }
1308 SelectCore::Values(_) => unreachable!("expected SELECT core"),
1309 },
1310 other => unreachable!("expected IN subquery, got {other:?}"),
1311 }
1312 }
1313
1314 #[test]
1315 fn test_not_in() {
1316 let expr = parse("x NOT IN (1, 2)");
1317 assert!(matches!(expr, Expr::In { not: true, .. }));
1318 }
1319
1320 #[test]
1321 fn test_in_table_name() {
1322 let expr = parse("x IN t");
1323 assert!(matches!(
1324 expr,
1325 Expr::In {
1326 not: false,
1327 set: InSet::Table(_),
1328 ..
1329 }
1330 ));
1331 }
1332
1333 #[test]
1334 fn test_not_in_table_name() {
1335 let expr = parse("x NOT IN t");
1336 assert!(matches!(
1337 expr,
1338 Expr::In {
1339 not: true,
1340 set: InSet::Table(_),
1341 ..
1342 }
1343 ));
1344 }
1345
1346 #[test]
1347 fn test_in_schema_table_name() {
1348 let expr = parse("x IN main.t");
1349 match expr {
1350 Expr::In {
1351 set: InSet::Table(name),
1352 ..
1353 } => {
1354 assert_eq!(name.schema.as_deref(), Some("main"));
1355 assert_eq!(name.name, "t");
1356 }
1357 other => unreachable!("expected IN table form, got {other:?}"),
1358 }
1359 }
1360
1361 #[test]
1364 fn test_between_and() {
1365 let expr = parse("x BETWEEN 1 AND 10");
1366 assert!(matches!(expr, Expr::Between { not: false, .. }));
1367 }
1368
1369 #[test]
1370 fn test_not_between() {
1371 let expr = parse("x NOT BETWEEN 1 AND 10");
1372 assert!(matches!(expr, Expr::Between { not: true, .. }));
1373 }
1374
1375 #[test]
1376 fn test_between_does_not_consume_outer_and() {
1377 let expr = parse("x BETWEEN 1 AND 10 AND y = 1");
1379 match &expr {
1380 Expr::BinaryOp {
1381 op: BinaryOp::And,
1382 left,
1383 ..
1384 } => assert!(matches!(left.as_ref(), Expr::Between { .. })),
1385 other => unreachable!("expected AND(BETWEEN, Eq), got {other:?}"),
1386 }
1387 }
1388
1389 #[test]
1392 fn test_like_pattern() {
1393 let expr = parse("name LIKE '%foo%'");
1394 assert!(matches!(
1395 expr,
1396 Expr::Like {
1397 op: LikeOp::Like,
1398 not: false,
1399 escape: None,
1400 ..
1401 }
1402 ));
1403 }
1404
1405 #[test]
1406 fn test_like_escape() {
1407 let expr = parse("name LIKE '%\\%%' ESCAPE '\\'");
1408 assert!(matches!(
1409 expr,
1410 Expr::Like {
1411 op: LikeOp::Like,
1412 escape: Some(_),
1413 ..
1414 }
1415 ));
1416 }
1417
1418 #[test]
1419 fn test_glob_pattern() {
1420 let expr = parse("path GLOB '*.rs'");
1421 assert!(matches!(
1422 expr,
1423 Expr::Like {
1424 op: LikeOp::Glob,
1425 not: false,
1426 ..
1427 }
1428 ));
1429 }
1430
1431 #[test]
1432 fn test_glob_character_class() {
1433 let expr = parse("name GLOB '[a-z]*'");
1434 match &expr {
1435 Expr::Like {
1436 op: LikeOp::Glob,
1437 pattern,
1438 ..
1439 } => assert!(matches!(
1440 pattern.as_ref(),
1441 Expr::Literal(Literal::String(s), _) if s == "[a-z]*"
1442 )),
1443 other => unreachable!("expected GLOB, got {other:?}"),
1444 }
1445 }
1446
1447 #[test]
1450 fn test_collate_override() {
1451 let expr = parse("name COLLATE NOCASE");
1452 match &expr {
1453 Expr::Collate { collation, .. } => {
1454 assert_eq!(collation, "NOCASE");
1455 }
1456 other => unreachable!("expected COLLATE, got {other:?}"),
1457 }
1458 }
1459
1460 #[test]
1463 fn test_json_arrow_operator() {
1464 let expr = parse("data -> 'key'");
1465 assert!(matches!(
1466 expr,
1467 Expr::JsonAccess {
1468 arrow: JsonArrow::Arrow,
1469 ..
1470 }
1471 ));
1472 }
1473
1474 #[test]
1475 fn test_json_double_arrow_operator() {
1476 let expr = parse("data ->> 'key'");
1477 assert!(matches!(
1478 expr,
1479 Expr::JsonAccess {
1480 arrow: JsonArrow::DoubleArrow,
1481 ..
1482 }
1483 ));
1484 }
1485
1486 #[test]
1489 fn test_is_null() {
1490 assert!(matches!(
1491 parse("42"),
1492 Expr::Literal(Literal::Integer(42), _)
1493 ));
1494 assert!(matches!(parse("3.14"), Expr::Literal(Literal::Float(_), _)));
1495 assert!(matches!(
1496 parse("'hello'"),
1497 Expr::Literal(Literal::String(_), _)
1498 ));
1499 assert!(matches!(parse("NULL"), Expr::Literal(Literal::Null, _)));
1500 assert!(matches!(parse("TRUE"), Expr::Literal(Literal::True, _)));
1501 assert!(matches!(parse("FALSE"), Expr::Literal(Literal::False, _)));
1502 }
1503
1504 #[test]
1505 fn test_placeholders() {
1506 assert!(matches!(
1507 parse("?"),
1508 Expr::Placeholder(PlaceholderType::Anonymous, _)
1509 ));
1510 assert!(matches!(
1511 parse("?1"),
1512 Expr::Placeholder(PlaceholderType::Numbered(1), _)
1513 ));
1514 assert!(matches!(
1515 parse(":name"),
1516 Expr::Placeholder(PlaceholderType::ColonNamed(_), _)
1517 ));
1518 }
1519
1520 #[test]
1523 fn test_column_bare() {
1524 match &parse("x") {
1525 Expr::Column(
1526 ColumnRef {
1527 table: None,
1528 column,
1529 },
1530 _,
1531 ) => assert_eq!(column.as_ref(), "x"),
1532 other => unreachable!("expected bare column, got {other:?}"),
1533 }
1534 }
1535
1536 #[test]
1537 fn test_column_qualified() {
1538 match &parse("t.x") {
1539 Expr::Column(
1540 ColumnRef {
1541 table: Some(t),
1542 column,
1543 },
1544 _,
1545 ) => {
1546 assert_eq!(t.as_ref(), "t");
1547 assert_eq!(column.as_ref(), "x");
1548 }
1549 other => unreachable!("expected qualified column, got {other:?}"),
1550 }
1551 }
1552
1553 #[test]
1556 fn test_concat_higher_than_add() {
1557 let expr = parse("a + b || c");
1559 match &expr {
1560 Expr::BinaryOp {
1561 op: BinaryOp::Add,
1562 right,
1563 ..
1564 } => assert!(matches!(
1565 right.as_ref(),
1566 Expr::BinaryOp {
1567 op: BinaryOp::Concat,
1568 ..
1569 }
1570 )),
1571 other => unreachable!("expected Add(a, Concat(b,c)), got {other:?}"),
1572 }
1573 }
1574
1575 #[test]
1578 fn test_parenthesized() {
1579 let expr = parse("(1 + 2) * 3");
1581 match &expr {
1582 Expr::BinaryOp {
1583 op: BinaryOp::Multiply,
1584 left,
1585 ..
1586 } => assert!(matches!(
1587 left.as_ref(),
1588 Expr::BinaryOp {
1589 op: BinaryOp::Add,
1590 ..
1591 }
1592 )),
1593 other => unreachable!("expected Mul(Add, 3), got {other:?}"),
1594 }
1595 }
1596
1597 #[test]
1600 fn test_is_operator() {
1601 assert!(matches!(
1602 parse("a IS b"),
1603 Expr::BinaryOp {
1604 op: BinaryOp::Is,
1605 ..
1606 }
1607 ));
1608 }
1609
1610 #[test]
1611 fn test_is_not_operator() {
1612 assert!(matches!(
1613 parse("a IS NOT b"),
1614 Expr::BinaryOp {
1615 op: BinaryOp::IsNot,
1616 ..
1617 }
1618 ));
1619 }
1620
1621 #[test]
1624 fn test_bitwise_ops() {
1625 let expr = parse("a & b | c");
1627 match &expr {
1628 Expr::BinaryOp {
1629 op: BinaryOp::BitOr,
1630 left,
1631 ..
1632 } => assert!(
1633 matches!(
1634 left.as_ref(),
1635 Expr::BinaryOp {
1636 op: BinaryOp::BitAnd,
1637 ..
1638 }
1639 ),
1640 "bitwise operators should be left-associative"
1641 ),
1642 other => unreachable!("expected BitOr(BitAnd, c), got {other:?}"),
1643 }
1644 }
1645
1646 #[test]
1647 fn test_bitnot() {
1648 assert!(matches!(
1649 parse("~x"),
1650 Expr::UnaryOp {
1651 op: UnaryOp::BitNot,
1652 ..
1653 }
1654 ));
1655 }
1656
1657 #[test]
1660 fn test_complex_where_clause() {
1661 let expr = parse("a > 1 AND b LIKE '%test%' OR NOT c IS NULL");
1662 assert!(matches!(
1663 expr,
1664 Expr::BinaryOp {
1665 op: BinaryOp::Or,
1666 ..
1667 }
1668 ));
1669 }
1670
1671 #[test]
1672 fn test_not_like_pattern() {
1673 assert!(matches!(
1674 parse("name NOT LIKE '%foo'"),
1675 Expr::Like {
1676 op: LikeOp::Like,
1677 not: true,
1678 ..
1679 }
1680 ));
1681 }
1682
1683 #[test]
1684 fn test_subquery_expr() {
1685 assert!(matches!(parse("(SELECT 1)"), Expr::Subquery(..)));
1686 }
1687
1688 #[test]
1696 fn test_pratt_level1_or_left_assoc() {
1697 let expr = parse("a OR b OR c");
1699 match &expr {
1700 Expr::BinaryOp {
1701 op: BinaryOp::Or,
1702 left,
1703 ..
1704 } => assert!(
1705 matches!(
1706 left.as_ref(),
1707 Expr::BinaryOp {
1708 op: BinaryOp::Or,
1709 ..
1710 }
1711 ),
1712 "OR should be left-associative"
1713 ),
1714 other => unreachable!("expected Or(Or(a,b), c), got {other:?}"),
1715 }
1716 }
1717
1718 #[test]
1720 fn test_pratt_level2_and_left_assoc() {
1721 let expr = parse("a AND b AND c");
1723 match &expr {
1724 Expr::BinaryOp {
1725 op: BinaryOp::And,
1726 left,
1727 ..
1728 } => assert!(
1729 matches!(
1730 left.as_ref(),
1731 Expr::BinaryOp {
1732 op: BinaryOp::And,
1733 ..
1734 }
1735 ),
1736 "AND should be left-associative"
1737 ),
1738 other => unreachable!("expected And(And(a,b), c), got {other:?}"),
1739 }
1740 }
1741
1742 #[test]
1744 fn test_pratt_level3_not_higher_than_and() {
1745 let expr = parse("NOT a AND b");
1747 match &expr {
1748 Expr::BinaryOp {
1749 op: BinaryOp::And,
1750 left,
1751 ..
1752 } => assert!(
1753 matches!(
1754 left.as_ref(),
1755 Expr::UnaryOp {
1756 op: UnaryOp::Not,
1757 ..
1758 }
1759 ),
1760 "NOT should bind tighter than AND"
1761 ),
1762 other => unreachable!("expected And(Not(a), b), got {other:?}"),
1763 }
1764 }
1765
1766 #[test]
1768 fn test_pratt_level4_equality_left_assoc() {
1769 let expr = parse("a = b != c");
1771 match &expr {
1772 Expr::BinaryOp {
1773 op: BinaryOp::Ne,
1774 left,
1775 ..
1776 } => assert!(
1777 matches!(
1778 left.as_ref(),
1779 Expr::BinaryOp {
1780 op: BinaryOp::Eq,
1781 ..
1782 }
1783 ),
1784 "equality operators should be left-associative at same level"
1785 ),
1786 other => unreachable!("expected Ne(Eq(a,b), c), got {other:?}"),
1787 }
1788 }
1789
1790 #[test]
1794 fn test_pratt_level4_vs_level5_eq_lt_boundary() {
1795 let expr = parse("a = b < c");
1798 match &expr {
1799 Expr::BinaryOp {
1800 op: BinaryOp::Eq,
1801 right,
1802 ..
1803 } => assert!(
1804 matches!(
1805 right.as_ref(),
1806 Expr::BinaryOp {
1807 op: BinaryOp::Lt,
1808 ..
1809 }
1810 ),
1811 "a = b < c MUST parse as a = (b < c): relational binds tighter"
1812 ),
1813 other => unreachable!("expected Eq(a, Lt(b,c)), got {other:?}"),
1814 }
1815 }
1816
1817 #[test]
1819 fn test_pratt_level4_vs_level5_ne_ge_boundary() {
1820 let expr = parse("a != b >= c");
1822 match &expr {
1823 Expr::BinaryOp {
1824 op: BinaryOp::Ne,
1825 right,
1826 ..
1827 } => assert!(
1828 matches!(
1829 right.as_ref(),
1830 Expr::BinaryOp {
1831 op: BinaryOp::Ge,
1832 ..
1833 }
1834 ),
1835 "a != b >= c must parse as a != (b >= c)"
1836 ),
1837 other => unreachable!("expected Ne(Ge(b,c)), got {other:?}"),
1838 }
1839 }
1840
1841 #[test]
1843 fn test_pratt_level5_relational_left_assoc() {
1844 let expr = parse("a < b >= c");
1846 match &expr {
1847 Expr::BinaryOp {
1848 op: BinaryOp::Ge,
1849 left,
1850 ..
1851 } => assert!(
1852 matches!(
1853 left.as_ref(),
1854 Expr::BinaryOp {
1855 op: BinaryOp::Lt,
1856 ..
1857 }
1858 ),
1859 "relational operators should be left-associative"
1860 ),
1861 other => unreachable!("expected Ge(Lt(a,b), c), got {other:?}"),
1862 }
1863 }
1864
1865 #[test]
1867 fn test_pratt_level6_bitwise_tighter_than_comparison() {
1868 let expr = parse("a < b & c");
1870 match &expr {
1871 Expr::BinaryOp {
1872 op: BinaryOp::Lt,
1873 right,
1874 ..
1875 } => assert!(
1876 matches!(
1877 right.as_ref(),
1878 Expr::BinaryOp {
1879 op: BinaryOp::BitAnd,
1880 ..
1881 }
1882 ),
1883 "bitwise should bind tighter than relational"
1884 ),
1885 other => unreachable!("expected Lt(a, BitAnd(b,c)), got {other:?}"),
1886 }
1887 }
1888
1889 #[test]
1891 fn test_pratt_level6_shifts_left_assoc() {
1892 let expr = parse("a << b >> c");
1894 match &expr {
1895 Expr::BinaryOp {
1896 op: BinaryOp::ShiftRight,
1897 left,
1898 ..
1899 } => assert!(
1900 matches!(
1901 left.as_ref(),
1902 Expr::BinaryOp {
1903 op: BinaryOp::ShiftLeft,
1904 ..
1905 }
1906 ),
1907 "shift operators should be left-associative"
1908 ),
1909 other => unreachable!("expected ShiftRight(ShiftLeft(a,b), c), got {other:?}"),
1910 }
1911 }
1912
1913 #[test]
1915 fn test_pratt_level7_add_sub_left_assoc() {
1916 let expr = parse("a + b - c");
1918 match &expr {
1919 Expr::BinaryOp {
1920 op: BinaryOp::Subtract,
1921 left,
1922 ..
1923 } => assert!(
1924 matches!(
1925 left.as_ref(),
1926 Expr::BinaryOp {
1927 op: BinaryOp::Add,
1928 ..
1929 }
1930 ),
1931 "add/sub should be left-associative"
1932 ),
1933 other => unreachable!("expected Sub(Add(a,b), c), got {other:?}"),
1934 }
1935 }
1936
1937 #[test]
1938 fn test_pratt_level7_add_sub_left_assoc_reverse() {
1939 let expr = parse("a - b + c");
1941 match &expr {
1942 Expr::BinaryOp {
1943 op: BinaryOp::Add,
1944 left,
1945 ..
1946 } => assert!(
1947 matches!(
1948 left.as_ref(),
1949 Expr::BinaryOp {
1950 op: BinaryOp::Subtract,
1951 ..
1952 }
1953 ),
1954 "add/sub should be left-associative"
1955 ),
1956 other => unreachable!("expected Add(Sub(a,b), c), got {other:?}"),
1957 }
1958 }
1959
1960 #[test]
1961 fn test_pratt_level9_concat_tighter_than_mul() {
1962 let expr = parse("a * b || c");
1964 match &expr {
1965 Expr::BinaryOp {
1966 op: BinaryOp::Multiply,
1967 right,
1968 ..
1969 } => assert!(
1970 matches!(
1971 right.as_ref(),
1972 Expr::BinaryOp {
1973 op: BinaryOp::Concat,
1974 ..
1975 }
1976 ),
1977 "concat should bind tighter than multiply"
1978 ),
1979 other => unreachable!("expected Mul(a, Concat(b,c)), got {other:?}"),
1980 }
1981 }
1982
1983 #[test]
1985 fn test_pratt_level8_mul_div_left_assoc() {
1986 let expr = parse("a * b / c");
1988 match &expr {
1989 Expr::BinaryOp {
1990 op: BinaryOp::Divide,
1991 left,
1992 ..
1993 } => assert!(
1994 matches!(
1995 left.as_ref(),
1996 Expr::BinaryOp {
1997 op: BinaryOp::Multiply,
1998 ..
1999 }
2000 ),
2001 "mul/div should be left-associative"
2002 ),
2003 other => unreachable!("expected Div(Mul(a,b), c), got {other:?}"),
2004 }
2005 }
2006
2007 #[test]
2008 fn test_pratt_level8_modulo() {
2009 let expr = parse("a * b % c");
2011 match &expr {
2012 Expr::BinaryOp {
2013 op: BinaryOp::Modulo,
2014 left,
2015 ..
2016 } => assert!(
2017 matches!(
2018 left.as_ref(),
2019 Expr::BinaryOp {
2020 op: BinaryOp::Multiply,
2021 ..
2022 }
2023 ),
2024 "modulo and multiply at same level, left-associative"
2025 ),
2026 other => unreachable!("expected Mod(Mul(a,b), c), got {other:?}"),
2027 }
2028 }
2029
2030 #[test]
2032 fn test_pratt_level9_concat_left_assoc() {
2033 let expr = parse("a || b || c");
2035 match &expr {
2036 Expr::BinaryOp {
2037 op: BinaryOp::Concat,
2038 left,
2039 ..
2040 } => assert!(
2041 matches!(
2042 left.as_ref(),
2043 Expr::BinaryOp {
2044 op: BinaryOp::Concat,
2045 ..
2046 }
2047 ),
2048 "concatenation should be left-associative"
2049 ),
2050 other => unreachable!("expected Concat(Concat(a,b), c), got {other:?}"),
2051 }
2052 }
2053
2054 #[test]
2055 fn test_pratt_level9_concat_left_assoc_reverse() {
2056 let expr = parse("a || b || c");
2058 match &expr {
2059 Expr::BinaryOp {
2060 op: BinaryOp::Concat,
2061 left,
2062 ..
2063 } => assert!(
2064 matches!(
2065 left.as_ref(),
2066 Expr::BinaryOp {
2067 op: BinaryOp::Concat,
2068 ..
2069 }
2070 ),
2071 "concatenation should be left-associative"
2072 ),
2073 other => unreachable!("expected Concat(Concat(a,b), c), got {other:?}"),
2074 }
2075 }
2076
2077 #[test]
2079 fn test_pratt_level10_collate_tighter_than_concat() {
2080 let expr = parse("a || b COLLATE NOCASE");
2082 match &expr {
2083 Expr::BinaryOp {
2084 op: BinaryOp::Concat,
2085 right,
2086 ..
2087 } => assert!(
2088 matches!(right.as_ref(), Expr::Collate { .. }),
2089 "COLLATE should bind tighter than concat"
2090 ),
2091 other => unreachable!("expected Concat(a, Collate(b)), got {other:?}"),
2092 }
2093 }
2094
2095 #[test]
2097 fn test_pratt_level11_unary_negate_tightest() {
2098 let expr = parse("-a * b");
2100 match &expr {
2101 Expr::BinaryOp {
2102 op: BinaryOp::Multiply,
2103 left,
2104 ..
2105 } => assert!(
2106 matches!(
2107 left.as_ref(),
2108 Expr::UnaryOp {
2109 op: UnaryOp::Negate,
2110 ..
2111 }
2112 ),
2113 "unary minus should bind tighter than multiply"
2114 ),
2115 other => unreachable!("expected Mul(Negate(a), b), got {other:?}"),
2116 }
2117 }
2118
2119 #[test]
2120 fn test_pratt_level11_bitnot_tightest() {
2121 let expr = parse("~a + b");
2123 match &expr {
2124 Expr::BinaryOp {
2125 op: BinaryOp::Add,
2126 left,
2127 ..
2128 } => assert!(
2129 matches!(
2130 left.as_ref(),
2131 Expr::UnaryOp {
2132 op: UnaryOp::BitNot,
2133 ..
2134 }
2135 ),
2136 "bitwise NOT should bind tighter than addition"
2137 ),
2138 other => unreachable!("expected Add(BitNot(a), b), got {other:?}"),
2139 }
2140 }
2141
2142 #[test]
2144 fn test_pratt_escape_not_infix_operator() {
2145 let expr = parse("a LIKE b ESCAPE c");
2147 match &expr {
2148 Expr::Like {
2149 escape: Some(esc), ..
2150 } => assert!(
2151 matches!(esc.as_ref(), Expr::Column(_, _)),
2152 "ESCAPE should be parsed as suffix of LIKE, not standalone infix"
2153 ),
2154 other => unreachable!("expected Like with escape, got {other:?}"),
2155 }
2156 }
2157
2158 #[test]
2159 fn test_pratt_escape_glob_not_infix() {
2160 let expr = parse("a GLOB b ESCAPE c");
2162 match &expr {
2163 Expr::Like {
2164 op: LikeOp::Glob,
2165 escape: Some(_),
2166 ..
2167 } => {}
2168 other => unreachable!("expected Glob with escape, got {other:?}"),
2169 }
2170 }
2171
2172 #[test]
2174 fn test_pratt_error_recovery_multiple_errors() {
2175 use crate::parser::Parser;
2176 let mut p = Parser::from_sql("SELECT +; SELECT *; SELECT 1");
2177 let (stmts, errs) = p.parse_all();
2178 assert!(
2181 !stmts.is_empty(),
2182 "should recover and parse at least one valid statement"
2183 );
2184 assert!(
2185 !errs.is_empty(),
2186 "should collect at least one error from malformed statements"
2187 );
2188 }
2189
2190 #[test]
2192 fn test_pratt_complex_mixed_all_levels() {
2193 let expr = parse("NOT a = b + c * -d OR e < f AND g LIKE h");
2196 match &expr {
2198 Expr::BinaryOp {
2199 op: BinaryOp::Or,
2200 left,
2201 right,
2202 ..
2203 } => {
2204 assert!(
2206 matches!(
2207 left.as_ref(),
2208 Expr::UnaryOp {
2209 op: UnaryOp::Not,
2210 ..
2211 }
2212 ),
2213 "left of OR should be NOT(...)"
2214 );
2215 match right.as_ref() {
2217 Expr::BinaryOp {
2218 op: BinaryOp::And,
2219 left: and_left,
2220 right: and_right,
2221 ..
2222 } => {
2223 assert!(
2224 matches!(
2225 and_left.as_ref(),
2226 Expr::BinaryOp {
2227 op: BinaryOp::Lt,
2228 ..
2229 }
2230 ),
2231 "left of AND should be Lt(e,f)"
2232 );
2233 assert!(
2234 matches!(and_right.as_ref(), Expr::Like { .. }),
2235 "right of AND should be Like(g,h)"
2236 );
2237 }
2238 other => unreachable!("expected And(Lt, Like), got {other:?}"),
2239 }
2240
2241 if let Expr::UnaryOp {
2244 expr: not_inner, ..
2245 } = left.as_ref()
2246 {
2247 if let Expr::BinaryOp {
2248 op: BinaryOp::Eq,
2249 right: eq_right,
2250 ..
2251 } = not_inner.as_ref()
2252 {
2253 if let Expr::BinaryOp {
2254 op: BinaryOp::Add,
2255 right: add_right,
2256 ..
2257 } = eq_right.as_ref()
2258 {
2259 if let Expr::BinaryOp {
2260 op: BinaryOp::Multiply,
2261 right: mul_right,
2262 ..
2263 } = add_right.as_ref()
2264 {
2265 assert!(
2266 matches!(
2267 mul_right.as_ref(),
2268 Expr::UnaryOp {
2269 op: UnaryOp::Negate,
2270 ..
2271 }
2272 ),
2273 "deepest: negate"
2274 );
2275 } else {
2276 unreachable!("expected Mul in add_right");
2277 }
2278 } else {
2279 unreachable!("expected Add in eq_right");
2280 }
2281 } else {
2282 unreachable!("expected Eq inside NOT");
2283 }
2284 }
2285 }
2286 other => unreachable!("expected Or(Not(...), And(...)), got {other:?}"),
2287 }
2288 }
2289
2290 #[test]
2292 fn test_pratt_json_same_precedence_as_concat() {
2293 let expr = parse("a || b -> c");
2295 match &expr {
2296 Expr::JsonAccess {
2297 expr: left,
2298 path: right,
2299 arrow: JsonArrow::Arrow,
2300 ..
2301 } => {
2302 assert!(
2303 matches!(
2304 left.as_ref(),
2305 Expr::BinaryOp {
2306 op: BinaryOp::Concat,
2307 ..
2308 }
2309 ),
2310 "left side should be concat expression"
2311 );
2312 assert!(
2313 matches!(right.as_ref(), Expr::Column(_, _)),
2314 "path should remain the right-hand expression"
2315 );
2316 }
2317 other => unreachable!("expected JsonAccess(Concat(a,b), c), got {other:?}"),
2318 }
2319 }
2320
2321 #[test]
2322 fn test_pratt_double_arrow_same_precedence_as_concat() {
2323 let expr = parse("a || b ->> c");
2324 assert!(
2325 matches!(
2326 expr,
2327 Expr::JsonAccess {
2328 arrow: JsonArrow::DoubleArrow,
2329 ..
2330 }
2331 ),
2332 "double-arrow should parse as JsonAccess at the same precedence level as concat"
2333 );
2334 }
2335}