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