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