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