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