1use sparrowdb_common::{Error, Result};
7
8use crate::ast::{
9 BinOpKind, CallStatement, CreateStatement, EdgeDir, ExistsPattern, Expr, ListPredicateKind,
10 Literal, MatchCreateStatement, MatchMergeRelStatement, MatchMutateStatement,
11 MatchOptionalMatchStatement, MatchStatement, MergeStatement, Mutation, NodePattern,
12 OptionalMatchStatement, PathPattern, PipelineStage, PipelineStatement, PropEntry, RelPattern,
13 ReturnClause, ReturnItem, ShortestPathExpr, SortDir, Statement, UnionStatement,
14 UnwindStatement, WithClause, WithItem,
15};
16use crate::lexer::{tokenize, Token};
17
18fn token_keyword_name(tok: &Token) -> Option<&'static str> {
22 match tok {
23 Token::Match => Some("MATCH"),
24 Token::Create => Some("CREATE"),
25 Token::Return => Some("RETURN"),
26 Token::Where => Some("WHERE"),
27 Token::Not => Some("NOT"),
28 Token::And => Some("AND"),
29 Token::Or => Some("OR"),
30 Token::Order => Some("ORDER"),
31 Token::By => Some("BY"),
32 Token::Asc => Some("ASC"),
33 Token::Desc => Some("DESC"),
34 Token::Limit => Some("LIMIT"),
35 Token::Skip => Some("SKIP"),
36 Token::Distinct => Some("DISTINCT"),
37 Token::Optional => Some("OPTIONAL"),
38 Token::Union => Some("UNION"),
39 Token::Unwind => Some("UNWIND"),
40 Token::Delete => Some("DELETE"),
41 Token::Detach => Some("DETACH"),
42 Token::Set => Some("SET"),
43 Token::Merge => Some("MERGE"),
44 Token::Checkpoint => Some("CHECKPOINT"),
45 Token::Optimize => Some("OPTIMIZE"),
46 Token::Contains => Some("CONTAINS"),
47 Token::StartsWith => Some("STARTS"),
48 Token::EndsWith => Some("ENDS"),
49 Token::Count => Some("COUNT"),
50 Token::Null => Some("NULL"),
51 Token::True => Some("TRUE"),
52 Token::False => Some("FALSE"),
53 Token::As => Some("AS"),
54 Token::With => Some("WITH"),
55 Token::Exists => Some("EXISTS"),
56 Token::In => Some("IN"),
57 Token::Any => Some("ANY"),
58 Token::All => Some("ALL"),
59 Token::NoneKw => Some("NONE"),
60 Token::Single => Some("SINGLE"),
61 Token::Is => Some("IS"),
62 Token::Call => Some("CALL"),
63 Token::Yield => Some("YIELD"),
64 Token::Case => Some("CASE"),
65 Token::When => Some("WHEN"),
66 Token::Then => Some("THEN"),
67 Token::Else => Some("ELSE"),
68 Token::End => Some("END"),
69 Token::Index => Some("INDEX"),
70 Token::On => Some("ON"),
71 Token::Constraint => Some("CONSTRAINT"),
72 Token::Assert => Some("ASSERT"),
73 _ => None,
74 }
75}
76
77pub fn parse(input: &str) -> Result<Statement> {
80 if input.trim().is_empty() {
81 return Err(Error::InvalidArgument("empty input".into()));
82 }
83 let tokens = tokenize(input)?;
84 let mut p = Parser::new(tokens);
85 let stmt = p.parse_statement()?;
86
87 let stmt = if matches!(p.peek(), Token::Union) {
89 p.advance();
90 let all = if matches!(p.peek(), Token::All)
91 || matches!(p.peek(), Token::Ident(ref s) if s.to_uppercase() == "ALL")
92 {
93 p.advance();
94 true
95 } else {
96 false
97 };
98 let right = p.parse_statement()?;
99 Statement::Union(UnionStatement {
100 left: Box::new(stmt),
101 right: Box::new(right),
102 all,
103 })
104 } else {
105 stmt
106 };
107
108 if matches!(p.peek(), Token::Semicolon) {
110 p.advance();
111 }
112 if !matches!(p.peek(), Token::Eof) {
114 return Err(Error::InvalidArgument(format!(
115 "unexpected trailing token: {:?}",
116 p.peek()
117 )));
118 }
119 Ok(stmt)
120}
121
122struct Parser {
125 tokens: Vec<Token>,
126 pos: usize,
127}
128
129impl Parser {
130 fn new(tokens: Vec<Token>) -> Self {
131 Parser { tokens, pos: 0 }
132 }
133
134 fn peek(&self) -> &Token {
135 &self.tokens[self.pos]
136 }
137
138 fn peek2(&self) -> &Token {
139 if self.pos + 1 < self.tokens.len() {
140 &self.tokens[self.pos + 1]
141 } else {
142 &Token::Eof
143 }
144 }
145
146 fn advance(&mut self) -> &Token {
147 let tok = &self.tokens[self.pos];
148 if self.pos + 1 < self.tokens.len() {
149 self.pos += 1;
150 }
151 tok
152 }
153
154 fn expect_ident(&mut self) -> Result<String> {
155 match self.advance().clone() {
156 Token::Ident(s) => Ok(s),
157 other => Err(Error::InvalidArgument(format!(
158 "expected identifier, got {:?}",
159 other
160 ))),
161 }
162 }
163
164 fn expect_label_or_type(&mut self) -> Result<String> {
173 let tok = self.advance().clone();
174 match tok {
175 Token::Ident(s) => Ok(s),
176 ref kw => token_keyword_name(kw)
177 .map(|s| s.to_string())
178 .ok_or_else(|| {
179 Error::InvalidArgument(format!("expected label/type name, got {:?}", tok))
180 }),
181 }
182 }
183
184 fn expect_tok(&mut self, expected: &Token) -> Result<()> {
185 let got = self.advance().clone();
186 if &got == expected {
187 Ok(())
188 } else {
189 Err(Error::InvalidArgument(format!(
190 "expected {:?}, got {:?}",
191 expected, got
192 )))
193 }
194 }
195
196 fn advance_as_prop_name(&mut self) -> Result<String> {
204 match self.advance().clone() {
205 Token::Ident(s) => Ok(s),
206 Token::Count => Ok("count".into()),
209 Token::With => Ok("with".into()),
210 Token::As => Ok("as".into()),
211 Token::In => Ok("in".into()),
212 Token::Is => Ok("is".into()),
213 Token::Not => Ok("not".into()),
214 Token::And => Ok("and".into()),
215 Token::Or => Ok("or".into()),
216 Token::Contains => Ok("contains".into()),
217 Token::StartsWith => Ok("starts".into()),
218 Token::EndsWith => Ok("ends".into()),
219 Token::Null => Ok("null".into()),
220 Token::True => Ok("true".into()),
221 Token::False => Ok("false".into()),
222 Token::Set => Ok("set".into()),
223 Token::Delete => Ok("delete".into()),
224 Token::Detach => Ok("detach".into()),
225 Token::Merge => Ok("merge".into()),
226 Token::Match => Ok("match".into()),
227 Token::Where => Ok("where".into()),
228 Token::Return => Ok("return".into()),
229 Token::Order => Ok("order".into()),
230 Token::By => Ok("by".into()),
231 Token::Asc => Ok("asc".into()),
232 Token::Desc => Ok("desc".into()),
233 Token::Limit => Ok("limit".into()),
234 Token::Skip => Ok("skip".into()),
235 Token::Distinct => Ok("distinct".into()),
236 Token::Optional => Ok("optional".into()),
237 Token::Union => Ok("union".into()),
238 Token::Unwind => Ok("unwind".into()),
239 Token::Create => Ok("create".into()),
240 Token::Exists => Ok("exists".into()),
241 Token::Any => Ok("any".into()),
242 Token::All => Ok("all".into()),
243 Token::NoneKw => Ok("none".into()),
244 Token::Single => Ok("single".into()),
245 Token::Call => Ok("call".into()),
246 Token::Yield => Ok("yield".into()),
247 Token::Case => Ok("case".into()),
248 Token::When => Ok("when".into()),
249 Token::Then => Ok("then".into()),
250 Token::Else => Ok("else".into()),
251 Token::End => Ok("end".into()),
252 Token::Index => Ok("index".into()),
253 Token::On => Ok("on".into()),
254 Token::Constraint => Ok("constraint".into()),
255 Token::Assert => Ok("assert".into()),
256 other => Err(Error::InvalidArgument(format!(
257 "expected property name, got {:?}",
258 other
259 ))),
260 }
261 }
262}
263
264impl Parser {
267 fn parse_statement(&mut self) -> Result<Statement> {
268 match self.peek().clone() {
269 Token::Match => self.parse_match_or_match_mutate(),
270 Token::Create => self.parse_create(),
271 Token::Merge => self.parse_merge(),
272 Token::Checkpoint => {
273 self.advance();
274 Ok(Statement::Checkpoint)
275 }
276 Token::Optimize => {
277 self.advance();
278 Ok(Statement::Optimize)
279 }
280 Token::Optional => self.parse_optional_match(),
281 Token::Union => Err(Error::InvalidArgument(
282 "unexpected UNION: use 'MATCH ... RETURN ... UNION MATCH ... RETURN ...'".into(),
283 )),
284 Token::Unwind => self.parse_unwind(),
285 Token::Return => self.parse_standalone_return(),
287 Token::Call => self.parse_call(),
289 other => Err(Error::InvalidArgument(format!(
290 "unexpected token at statement start: {:?}",
291 other
292 ))),
293 }
294 }
295
296 fn parse_standalone_return(&mut self) -> Result<Statement> {
302 self.expect_tok(&Token::Return)?;
303 let distinct = if matches!(self.peek(), Token::Distinct) {
304 self.advance();
305 true
306 } else {
307 false
308 };
309 let items = self.parse_return_items()?;
310 Ok(Statement::Match(MatchStatement {
311 pattern: vec![],
312 where_clause: None,
313 return_clause: ReturnClause { items },
314 order_by: vec![],
315 skip: None,
316 limit: None,
317 distinct,
318 }))
319 }
320
321 fn parse_match_or_match_mutate(&mut self) -> Result<Statement> {
324 self.expect_tok(&Token::Match)?;
326
327 let patterns = self.parse_pattern_list()?;
328
329 match self.peek().clone() {
330 Token::Create => {
331 self.advance();
333 let create = self.parse_create_body()?;
334 Ok(Statement::MatchCreate(MatchCreateStatement {
335 match_patterns: patterns,
336 match_props: vec![],
337 create,
338 }))
339 }
340 Token::Set => {
341 self.advance();
343 let var = self.expect_ident()?;
344 self.expect_tok(&Token::Dot)?;
345 let prop = self.expect_ident()?;
346 self.expect_tok(&Token::Eq)?;
347 let value = self.parse_expr()?;
348 Ok(Statement::MatchMutate(MatchMutateStatement {
349 match_patterns: patterns,
350 where_clause: None,
351 mutation: Mutation::Set { var, prop, value },
352 }))
353 }
354 Token::Delete => {
355 self.advance();
357 let var = self.expect_ident()?;
358 Ok(Statement::MatchMutate(MatchMutateStatement {
359 match_patterns: patterns,
360 where_clause: None,
361 mutation: Mutation::Delete { var },
362 }))
363 }
364 Token::Where => {
365 self.advance();
367 let where_expr = self.parse_expr()?;
368 match self.peek().clone() {
369 Token::Set => {
370 self.advance();
371 let var = self.expect_ident()?;
372 self.expect_tok(&Token::Dot)?;
373 let prop = self.expect_ident()?;
374 self.expect_tok(&Token::Eq)?;
375 let value = self.parse_expr()?;
376 Ok(Statement::MatchMutate(MatchMutateStatement {
377 match_patterns: patterns,
378 where_clause: Some(where_expr),
379 mutation: Mutation::Set { var, prop, value },
380 }))
381 }
382 Token::Delete => {
383 self.advance();
384 let var = self.expect_ident()?;
385 Ok(Statement::MatchMutate(MatchMutateStatement {
386 match_patterns: patterns,
387 where_clause: Some(where_expr),
388 mutation: Mutation::Delete { var },
389 }))
390 }
391 Token::With => {
392 self.parse_with_pipeline(patterns, Some(where_expr))
394 }
395 Token::Merge => {
396 self.parse_match_merge_rel_tail(patterns, Some(where_expr))
398 }
399 _ => {
400 self.finish_match_return(patterns, Some(where_expr))
402 }
403 }
404 }
405 Token::With => {
406 self.parse_with_pipeline(patterns, None)
408 }
409 Token::Merge => {
410 self.parse_match_merge_rel_tail(patterns, None)
412 }
413 Token::Return
414 | Token::Order
415 | Token::Skip
416 | Token::Limit
417 | Token::Eof
418 | Token::Semicolon => self.finish_match_return(patterns, None),
419 Token::Optional => {
420 self.parse_match_optional_match_tail(patterns, None)
422 }
423 other => Err(Error::InvalidArgument(format!(
424 "unexpected token after MATCH pattern: {:?}",
425 other
426 ))),
427 }
428 }
429
430 fn parse_optional_match(&mut self) -> Result<Statement> {
434 self.expect_tok(&Token::Optional)?;
435 self.expect_tok(&Token::Match)?;
436
437 let patterns = self.parse_pattern_list()?;
438
439 let where_clause = if matches!(self.peek(), Token::Where) {
441 self.advance();
442 Some(self.parse_expr()?)
443 } else {
444 None
445 };
446
447 self.expect_tok(&Token::Return)?;
449 let distinct = if matches!(self.peek(), Token::Distinct) {
450 self.advance();
451 true
452 } else {
453 false
454 };
455 let items = self.parse_return_items()?;
456 let return_clause = ReturnClause { items };
457
458 let order_by = if matches!(self.peek(), Token::Order) {
460 self.advance();
461 self.expect_tok(&Token::By)?;
462 self.parse_order_by_items()?
463 } else {
464 vec![]
465 };
466
467 let skip = if matches!(self.peek(), Token::Skip) {
469 self.advance();
470 match self.advance().clone() {
471 Token::Integer(n) => {
472 if n < 0 {
473 return Err(Error::InvalidArgument("SKIP must be non-negative".into()));
474 }
475 Some(n as u64)
476 }
477 other => {
478 return Err(Error::InvalidArgument(format!(
479 "expected integer after SKIP, got {:?}",
480 other
481 )))
482 }
483 }
484 } else {
485 None
486 };
487
488 let limit = if matches!(self.peek(), Token::Limit) {
490 self.advance();
491 match self.advance().clone() {
492 Token::Integer(n) => {
493 if n < 0 {
494 return Err(Error::InvalidArgument("LIMIT must be non-negative".into()));
495 }
496 Some(n as u64)
497 }
498 other => {
499 return Err(Error::InvalidArgument(format!(
500 "expected integer after LIMIT, got {:?}",
501 other
502 )))
503 }
504 }
505 } else {
506 None
507 };
508
509 Ok(Statement::OptionalMatch(OptionalMatchStatement {
510 pattern: patterns,
511 where_clause,
512 return_clause,
513 order_by,
514 skip,
515 limit,
516 distinct,
517 }))
518 }
519
520 fn parse_match_optional_match_tail(
526 &mut self,
527 match_patterns: Vec<PathPattern>,
528 match_where: Option<Expr>,
529 ) -> Result<Statement> {
530 self.expect_tok(&Token::Optional)?;
532 self.expect_tok(&Token::Match)?;
533
534 let optional_patterns = self.parse_pattern_list()?;
535
536 let optional_where = if matches!(self.peek(), Token::Where) {
538 self.advance();
539 Some(self.parse_expr()?)
540 } else {
541 None
542 };
543
544 self.expect_tok(&Token::Return)?;
546 let distinct = if matches!(self.peek(), Token::Distinct) {
547 self.advance();
548 true
549 } else {
550 false
551 };
552 let items = self.parse_return_items()?;
553 let return_clause = ReturnClause { items };
554
555 let order_by = if matches!(self.peek(), Token::Order) {
557 self.advance();
558 self.expect_tok(&Token::By)?;
559 self.parse_order_by_items()?
560 } else {
561 vec![]
562 };
563
564 let skip = if matches!(self.peek(), Token::Skip) {
566 self.advance();
567 match self.advance().clone() {
568 Token::Integer(n) => {
569 if n < 0 {
570 return Err(Error::InvalidArgument("SKIP must be non-negative".into()));
571 }
572 Some(n as u64)
573 }
574 other => {
575 return Err(Error::InvalidArgument(format!(
576 "expected integer after SKIP, got {:?}",
577 other
578 )))
579 }
580 }
581 } else {
582 None
583 };
584
585 let limit = if matches!(self.peek(), Token::Limit) {
587 self.advance();
588 match self.advance().clone() {
589 Token::Integer(n) => {
590 if n < 0 {
591 return Err(Error::InvalidArgument("LIMIT must be non-negative".into()));
592 }
593 Some(n as u64)
594 }
595 other => {
596 return Err(Error::InvalidArgument(format!(
597 "expected integer after LIMIT, got {:?}",
598 other
599 )))
600 }
601 }
602 } else {
603 None
604 };
605
606 Ok(Statement::MatchOptionalMatch(MatchOptionalMatchStatement {
607 match_patterns,
608 match_where,
609 optional_patterns,
610 optional_where,
611 return_clause,
612 order_by,
613 skip,
614 limit,
615 distinct,
616 }))
617 }
618
619 fn finish_match_return(
622 &mut self,
623 patterns: Vec<PathPattern>,
624 pre_where: Option<Expr>,
625 ) -> Result<Statement> {
626 let where_clause = if pre_where.is_some() { pre_where } else { None };
628
629 let (distinct, return_clause) = if matches!(self.peek(), Token::Return) {
631 self.advance();
632 let distinct = if matches!(self.peek(), Token::Distinct) {
633 self.advance();
634 true
635 } else {
636 false
637 };
638 let items = self.parse_return_items()?;
639 (distinct, ReturnClause { items })
640 } else {
641 return Err(Error::InvalidArgument("expected RETURN clause".into()));
642 };
643
644 let order_by = if matches!(self.peek(), Token::Order) {
646 self.advance();
647 self.expect_tok(&Token::By)?;
648 self.parse_order_by_items()?
649 } else {
650 vec![]
651 };
652
653 let skip = if matches!(self.peek(), Token::Skip) {
655 self.advance();
656 match self.advance().clone() {
657 Token::Integer(n) => {
658 if n < 0 {
659 return Err(Error::InvalidArgument("SKIP must be non-negative".into()));
660 }
661 Some(n as u64)
662 }
663 other => {
664 return Err(Error::InvalidArgument(format!(
665 "expected integer after SKIP, got {:?}",
666 other
667 )))
668 }
669 }
670 } else {
671 None
672 };
673
674 let limit = if matches!(self.peek(), Token::Limit) {
676 self.advance();
677 match self.advance().clone() {
678 Token::Integer(n) => {
679 if n < 0 {
680 return Err(Error::InvalidArgument("LIMIT must be non-negative".into()));
681 }
682 Some(n as u64)
683 }
684 other => {
685 return Err(Error::InvalidArgument(format!(
686 "expected integer after LIMIT, got {:?}",
687 other
688 )))
689 }
690 }
691 } else {
692 None
693 };
694
695 Ok(Statement::Match(MatchStatement {
696 pattern: patterns,
697 where_clause,
698 return_clause,
699 order_by,
700 skip,
701 limit,
702 distinct,
703 }))
704 }
705
706 fn parse_with_pipeline(
710 &mut self,
711 patterns: Vec<PathPattern>,
712 match_where: Option<Expr>,
713 ) -> Result<Statement> {
714 use crate::ast::MatchWithStatement;
715
716 self.expect_tok(&Token::With)?;
718
719 let mut items: Vec<WithItem> = Vec::new();
721 loop {
722 let expr = self.parse_expr()?;
723 self.expect_tok(&Token::As)?;
724 let alias = self.expect_ident()?;
725 items.push(WithItem { expr, alias });
726 if matches!(self.peek(), Token::Comma) {
727 self.advance();
728 } else {
729 break;
730 }
731 }
732
733 let with_where = if matches!(self.peek(), Token::Where) {
735 self.advance();
736 Some(self.parse_expr()?)
737 } else {
738 None
739 };
740
741 let with_clause = WithClause {
742 items,
743 where_clause: with_where,
744 };
745
746 let with_order_by = if matches!(self.peek(), Token::Order) {
749 self.advance();
750 self.expect_tok(&Token::By)?;
751 self.parse_order_by_items()?
752 } else {
753 vec![]
754 };
755
756 let with_skip = if matches!(self.peek(), Token::Skip) {
757 self.advance();
758 match self.advance().clone() {
759 Token::Integer(n) => {
760 if n < 0 {
761 return Err(Error::InvalidArgument("SKIP must be non-negative".into()));
762 }
763 Some(n as u64)
764 }
765 other => {
766 return Err(Error::InvalidArgument(format!(
767 "expected integer after SKIP, got {:?}",
768 other
769 )))
770 }
771 }
772 } else {
773 None
774 };
775
776 let with_limit = if matches!(self.peek(), Token::Limit) {
777 self.advance();
778 match self.advance().clone() {
779 Token::Integer(n) => {
780 if n < 0 {
781 return Err(Error::InvalidArgument("LIMIT must be non-negative".into()));
782 }
783 Some(n as u64)
784 }
785 other => {
786 return Err(Error::InvalidArgument(format!(
787 "expected integer after LIMIT, got {:?}",
788 other
789 )))
790 }
791 }
792 } else {
793 None
794 };
795
796 match self.peek().clone() {
799 Token::Return => {
800 self.advance(); let distinct = if matches!(self.peek(), Token::Distinct) {
803 self.advance();
804 true
805 } else {
806 false
807 };
808 let return_items = self.parse_return_items()?;
809 let return_clause = ReturnClause {
810 items: return_items,
811 };
812
813 let order_by = if matches!(self.peek(), Token::Order) {
815 self.advance();
816 self.expect_tok(&Token::By)?;
817 self.parse_order_by_items()?
818 } else {
819 with_order_by
820 };
821
822 let skip = if matches!(self.peek(), Token::Skip) {
823 self.advance();
824 match self.advance().clone() {
825 Token::Integer(n) => {
826 if n < 0 {
827 return Err(Error::InvalidArgument(
828 "SKIP must be non-negative".into(),
829 ));
830 }
831 Some(n as u64)
832 }
833 other => {
834 return Err(Error::InvalidArgument(format!(
835 "expected integer after SKIP, got {:?}",
836 other
837 )))
838 }
839 }
840 } else {
841 with_skip
842 };
843
844 let limit = if matches!(self.peek(), Token::Limit) {
845 self.advance();
846 match self.advance().clone() {
847 Token::Integer(n) => {
848 if n < 0 {
849 return Err(Error::InvalidArgument(
850 "LIMIT must be non-negative".into(),
851 ));
852 }
853 Some(n as u64)
854 }
855 other => {
856 return Err(Error::InvalidArgument(format!(
857 "expected integer after LIMIT, got {:?}",
858 other
859 )))
860 }
861 }
862 } else {
863 with_limit
864 };
865
866 Ok(Statement::MatchWith(MatchWithStatement {
867 match_patterns: patterns,
868 match_where,
869 with_clause,
870 return_clause,
871 order_by,
872 skip,
873 limit,
874 distinct,
875 }))
876 }
877 Token::Match | Token::With | Token::Unwind => {
879 let first_with_stage = PipelineStage::With {
880 clause: with_clause,
881 order_by: with_order_by,
882 skip: with_skip,
883 limit: with_limit,
884 };
885 self.parse_pipeline_continuation(
886 Some(patterns),
887 match_where,
888 None,
889 vec![first_with_stage],
890 )
891 }
892 other => Err(Error::InvalidArgument(format!(
893 "expected RETURN, MATCH, WITH, or UNWIND after WITH clause, got {:?}",
894 other
895 ))),
896 }
897 }
898
899 fn parse_pipeline_continuation(
903 &mut self,
904 leading_match: Option<Vec<PathPattern>>,
905 leading_where: Option<Expr>,
906 leading_unwind: Option<(crate::ast::Expr, String)>,
907 mut stages: Vec<PipelineStage>,
908 ) -> Result<Statement> {
909 loop {
910 match self.peek().clone() {
911 Token::Match => {
912 self.advance(); let patterns = self.parse_pattern_list()?;
915 let where_clause = if matches!(self.peek(), Token::Where) {
916 self.advance();
917 Some(self.parse_expr()?)
918 } else {
919 None
920 };
921 stages.push(PipelineStage::Match {
922 patterns,
923 where_clause,
924 });
925 }
926 Token::With => {
927 self.advance(); let mut items: Vec<WithItem> = Vec::new();
930 loop {
931 let expr = self.parse_expr()?;
932 self.expect_tok(&Token::As)?;
933 let alias = self.expect_ident()?;
934 items.push(WithItem { expr, alias });
935 if matches!(self.peek(), Token::Comma) {
936 self.advance();
937 } else {
938 break;
939 }
940 }
941 let where_clause = if matches!(self.peek(), Token::Where) {
942 self.advance();
943 Some(self.parse_expr()?)
944 } else {
945 None
946 };
947 let clause = WithClause {
948 items,
949 where_clause,
950 };
951 let order_by = if matches!(self.peek(), Token::Order) {
953 self.advance();
954 self.expect_tok(&Token::By)?;
955 self.parse_order_by_items()?
956 } else {
957 vec![]
958 };
959 let skip = if matches!(self.peek(), Token::Skip) {
960 self.advance();
961 match self.advance().clone() {
962 Token::Integer(n) => {
963 if n < 0 {
964 return Err(Error::InvalidArgument(
965 "SKIP must be non-negative".into(),
966 ));
967 }
968 Some(n as u64)
969 }
970 other => {
971 return Err(Error::InvalidArgument(format!(
972 "expected integer after SKIP, got {:?}",
973 other
974 )))
975 }
976 }
977 } else {
978 None
979 };
980 let limit = if matches!(self.peek(), Token::Limit) {
981 self.advance();
982 match self.advance().clone() {
983 Token::Integer(n) => {
984 if n < 0 {
985 return Err(Error::InvalidArgument(
986 "LIMIT must be non-negative".into(),
987 ));
988 }
989 Some(n as u64)
990 }
991 other => {
992 return Err(Error::InvalidArgument(format!(
993 "expected integer after LIMIT, got {:?}",
994 other
995 )))
996 }
997 }
998 } else {
999 None
1000 };
1001 stages.push(PipelineStage::With {
1002 clause,
1003 order_by,
1004 skip,
1005 limit,
1006 });
1007 }
1008 Token::Unwind => {
1009 self.advance(); let alias = self.expect_ident()?;
1013 self.expect_tok(&Token::As)?;
1014 let new_alias = self.expect_ident()?;
1015 stages.push(PipelineStage::Unwind { alias, new_alias });
1016 }
1017 Token::Return => {
1018 self.advance(); let distinct = if matches!(self.peek(), Token::Distinct) {
1021 self.advance();
1022 true
1023 } else {
1024 false
1025 };
1026 let return_items = self.parse_return_items()?;
1027 let return_clause = ReturnClause {
1028 items: return_items,
1029 };
1030 let return_order_by = if matches!(self.peek(), Token::Order) {
1031 self.advance();
1032 self.expect_tok(&Token::By)?;
1033 self.parse_order_by_items()?
1034 } else {
1035 vec![]
1036 };
1037 let return_skip = if matches!(self.peek(), Token::Skip) {
1038 self.advance();
1039 match self.advance().clone() {
1040 Token::Integer(n) => {
1041 if n < 0 {
1042 return Err(Error::InvalidArgument(
1043 "SKIP must be non-negative".into(),
1044 ));
1045 }
1046 Some(n as u64)
1047 }
1048 other => {
1049 return Err(Error::InvalidArgument(format!(
1050 "expected integer after SKIP, got {:?}",
1051 other
1052 )))
1053 }
1054 }
1055 } else {
1056 None
1057 };
1058 let return_limit = if matches!(self.peek(), Token::Limit) {
1059 self.advance();
1060 match self.advance().clone() {
1061 Token::Integer(n) => {
1062 if n < 0 {
1063 return Err(Error::InvalidArgument(
1064 "LIMIT must be non-negative".into(),
1065 ));
1066 }
1067 Some(n as u64)
1068 }
1069 other => {
1070 return Err(Error::InvalidArgument(format!(
1071 "expected integer after LIMIT, got {:?}",
1072 other
1073 )))
1074 }
1075 }
1076 } else {
1077 None
1078 };
1079 return Ok(Statement::Pipeline(PipelineStatement {
1080 leading_match,
1081 leading_where,
1082 leading_unwind,
1083 stages,
1084 return_clause,
1085 return_order_by,
1086 return_skip,
1087 return_limit,
1088 distinct,
1089 }));
1090 }
1091 other => {
1092 return Err(Error::InvalidArgument(format!(
1093 "expected MATCH, WITH, UNWIND, or RETURN in pipeline, got {:?}",
1094 other
1095 )))
1096 }
1097 }
1098 }
1099 }
1100
1101 fn parse_merge(&mut self) -> Result<Statement> {
1107 self.expect_tok(&Token::Merge)?;
1108 self.expect_tok(&Token::LParen)?;
1109
1110 let var = if let Token::Ident(_) = self.peek().clone() {
1112 if matches!(self.peek2(), Token::Colon) {
1113 let name = match self.advance().clone() {
1115 Token::Ident(s) => s,
1116 _ => unreachable!(),
1117 };
1118 name
1119 } else {
1120 String::new()
1122 }
1123 } else {
1124 String::new()
1125 };
1126
1127 if !matches!(self.peek(), Token::Colon) {
1129 return Err(Error::InvalidArgument(
1130 "MERGE requires a label (e.g. MERGE (:Person {...}))".into(),
1131 ));
1132 }
1133 self.advance(); let label = self.expect_label_or_type()?;
1135
1136 let props = if matches!(self.peek(), Token::LBrace) {
1138 self.parse_prop_map()?
1139 } else {
1140 vec![]
1141 };
1142
1143 self.expect_tok(&Token::RParen)?;
1144
1145 let return_clause = if matches!(self.peek(), Token::Return) {
1147 self.advance(); let items = self.parse_return_items()?;
1149 Some(ReturnClause { items })
1150 } else {
1151 None
1152 };
1153
1154 Ok(Statement::Merge(MergeStatement {
1155 var,
1156 label,
1157 props,
1158 return_clause,
1159 }))
1160 }
1161
1162 fn parse_match_merge_rel_tail(
1166 &mut self,
1167 match_patterns: Vec<PathPattern>,
1168 where_clause: Option<Expr>,
1169 ) -> Result<Statement> {
1170 self.expect_tok(&Token::Merge)?;
1171
1172 let src_node = self.parse_node_pattern()?;
1173 let src_var = src_node.var;
1174
1175 if !matches!(self.peek(), Token::Dash | Token::Arrow | Token::LeftArrow) {
1176 return Err(Error::InvalidArgument(format!(
1177 "expected relationship pattern after node in MERGE, got {:?}",
1178 self.peek()
1179 )));
1180 }
1181 let rel_pat = self.parse_rel_pattern()?;
1182 if rel_pat.dir != EdgeDir::Outgoing {
1183 return Err(Error::InvalidArgument(
1184 "MERGE relationship pattern must use outgoing direction: (a)-[r:TYPE]->(b)".into(),
1185 ));
1186 }
1187
1188 let dst_node = self.parse_node_pattern()?;
1189 let dst_var = dst_node.var;
1190
1191 while matches!(self.peek(), Token::On) {
1193 self.advance(); self.skip_on_clause()?;
1195 }
1196
1197 Ok(Statement::MatchMergeRel(MatchMergeRelStatement {
1198 match_patterns,
1199 where_clause,
1200 src_var,
1201 rel_var: rel_pat.var,
1202 rel_type: rel_pat.rel_type,
1203 dst_var,
1204 }))
1205 }
1206
1207 fn skip_on_clause(&mut self) -> Result<()> {
1209 match self.peek() {
1210 Token::Create | Token::Match => {
1211 self.advance();
1212 }
1213 other => {
1214 return Err(Error::InvalidArgument(format!(
1215 "expected CREATE or MATCH after ON, got {:?}",
1216 other
1217 )));
1218 }
1219 }
1220 loop {
1221 match self.peek() {
1222 Token::Eof
1223 | Token::Semicolon
1224 | Token::Return
1225 | Token::With
1226 | Token::Merge
1227 | Token::On => break,
1228 _ => {
1229 self.advance();
1230 }
1231 }
1232 }
1233 Ok(())
1234 }
1235
1236 fn parse_create(&mut self) -> Result<Statement> {
1239 self.expect_tok(&Token::Create)?;
1240 if matches!(self.peek(), Token::Index) {
1241 self.advance();
1242 return self.parse_create_index();
1243 }
1244 if matches!(self.peek(), Token::Constraint) {
1245 self.advance();
1246 return self.parse_create_constraint();
1247 }
1248 let body = self.parse_create_body()?;
1249 Ok(Statement::Create(body))
1250 }
1251 fn parse_create_index(&mut self) -> Result<Statement> {
1252 self.expect_tok(&Token::On)?;
1253 self.expect_tok(&Token::Colon)?;
1254 let label = self.expect_label_or_type()?;
1255 self.expect_tok(&Token::LParen)?;
1256 let property = self.expect_ident()?;
1257 self.expect_tok(&Token::RParen)?;
1258 Ok(Statement::CreateIndex { label, property })
1259 }
1260 fn parse_create_constraint(&mut self) -> Result<Statement> {
1261 self.expect_tok(&Token::On)?;
1262 self.expect_tok(&Token::LParen)?;
1263 let _var = self.expect_ident()?;
1264 self.expect_tok(&Token::Colon)?;
1265 let label = self.expect_label_or_type()?;
1266 self.expect_tok(&Token::RParen)?;
1267 match self.advance().clone() {
1268 Token::Assert => {}
1269 other => {
1270 return Err(Error::InvalidArgument(format!(
1271 "expected ASSERT, got {:?}",
1272 other
1273 )))
1274 }
1275 }
1276 let _prop_var = self.expect_ident()?;
1277 self.expect_tok(&Token::Dot)?;
1278 let property = self.expect_ident()?;
1279 self.expect_tok(&Token::Is)?;
1280 match self.advance().clone() {
1281 Token::Ident(ref s) if s.eq_ignore_ascii_case("UNIQUE") => {}
1282 other => {
1283 return Err(Error::InvalidArgument(format!(
1284 "expected UNIQUE, got {:?}",
1285 other
1286 )))
1287 }
1288 }
1289 Ok(Statement::CreateConstraint { label, property })
1290 }
1291
1292 fn parse_unwind(&mut self) -> Result<Statement> {
1303 self.expect_tok(&Token::Unwind)?;
1304 let expr = self.parse_unwind_expr()?;
1305 self.expect_tok(&Token::As)?;
1306 let alias = self.expect_ident()?;
1307
1308 if matches!(self.peek(), Token::With | Token::Match) {
1312 return self.parse_pipeline_continuation(None, None, Some((expr, alias)), vec![]);
1313 }
1314
1315 self.expect_tok(&Token::Return)?;
1316 let items = self.parse_return_items()?;
1317 Ok(Statement::Unwind(UnwindStatement {
1318 expr,
1319 alias,
1320 return_clause: ReturnClause { items },
1321 }))
1322 }
1323
1324 fn parse_unwind_expr(&mut self) -> Result<Expr> {
1331 match self.peek().clone() {
1332 Token::LBracket => self.parse_list_literal(),
1333 Token::Param(p) => {
1334 self.advance();
1335 Ok(Expr::Literal(Literal::Param(p)))
1336 }
1337 Token::Ident(_) => {
1338 self.parse_atom()
1340 }
1341 other => Err(Error::InvalidArgument(format!(
1342 "UNWIND expects a list literal [..], $param, or a function call, got {:?}",
1343 other
1344 ))),
1345 }
1346 }
1347
1348 fn parse_list_literal(&mut self) -> Result<Expr> {
1350 self.expect_tok(&Token::LBracket)?;
1351 let mut elems = Vec::new();
1352 if !matches!(self.peek(), Token::RBracket) {
1353 loop {
1354 elems.push(self.parse_expr()?);
1355 if matches!(self.peek(), Token::Comma) {
1356 self.advance();
1357 } else {
1358 break;
1359 }
1360 }
1361 }
1362 self.expect_tok(&Token::RBracket)?;
1363 Ok(Expr::List(elems))
1364 }
1365
1366 fn parse_create_body(&mut self) -> Result<CreateStatement> {
1367 let mut nodes = Vec::new();
1368 let mut edges: Vec<(String, RelPattern, String)> = Vec::new();
1369
1370 loop {
1371 if !matches!(self.peek(), Token::LParen) {
1372 break;
1373 }
1374 let node = self.parse_node_pattern()?;
1376 let node_var = node.var.clone();
1377
1378 if matches!(self.peek(), Token::Dash | Token::Arrow | Token::LeftArrow) {
1379 nodes.push(node);
1385 let rel = self.parse_rel_pattern()?;
1386 let dst_node = self.parse_node_pattern()?;
1387 let dst_var = dst_node.var.clone();
1388 edges.push((node_var, rel, dst_var));
1389 nodes.push(dst_node);
1390 } else {
1391 nodes.push(node);
1392 }
1393
1394 if matches!(self.peek(), Token::Comma) {
1395 self.advance();
1396 } else {
1397 break;
1398 }
1399 }
1400
1401 if nodes.is_empty() && edges.is_empty() {
1402 return Err(Error::InvalidArgument(
1403 "CREATE body must contain at least one node or edge pattern".into(),
1404 ));
1405 }
1406
1407 Ok(CreateStatement { nodes, edges })
1408 }
1409
1410 fn parse_pattern_list(&mut self) -> Result<Vec<PathPattern>> {
1413 let mut patterns = Vec::new();
1414 patterns.push(self.parse_path_pattern()?);
1415 while matches!(self.peek(), Token::Comma) {
1416 self.advance();
1417 patterns.push(self.parse_path_pattern()?);
1418 }
1419 Ok(patterns)
1420 }
1421
1422 fn parse_path_pattern(&mut self) -> Result<PathPattern> {
1423 let mut nodes = Vec::new();
1424 let mut rels = Vec::new();
1425
1426 nodes.push(self.parse_node_pattern()?);
1427
1428 while matches!(self.peek(), Token::Dash | Token::Arrow | Token::LeftArrow) {
1429 let rel = self.parse_rel_pattern()?;
1431 nodes.push(self.parse_node_pattern()?);
1432 rels.push(rel);
1433 }
1434
1435 Ok(PathPattern { nodes, rels })
1436 }
1437
1438 fn parse_node_pattern(&mut self) -> Result<NodePattern> {
1441 self.expect_tok(&Token::LParen)?;
1442
1443 let var = match self.peek().clone() {
1444 Token::Ident(s) if !matches!(self.peek2(), Token::LParen) => {
1445 self.advance();
1446 s
1447 }
1448 _ => String::new(),
1449 };
1450
1451 let mut labels = Vec::new();
1452 while matches!(self.peek(), Token::Colon) {
1453 self.advance();
1454 let label = self.expect_label_or_type()?;
1455 labels.push(label);
1456 }
1457
1458 let props = if matches!(self.peek(), Token::LBrace) {
1459 self.parse_prop_map()?
1460 } else {
1461 vec![]
1462 };
1463
1464 self.expect_tok(&Token::RParen)?;
1465 Ok(NodePattern { var, labels, props })
1466 }
1467
1468 fn parse_rel_pattern(&mut self) -> Result<RelPattern> {
1471 let incoming = if matches!(self.peek(), Token::LeftArrow) {
1473 self.advance();
1474 true
1475 } else if matches!(self.peek(), Token::Dash) {
1476 self.advance();
1477 false
1478 } else {
1479 return Err(Error::InvalidArgument(format!(
1480 "expected - or <- for relationship, got {:?}",
1481 self.peek()
1482 )));
1483 };
1484
1485 self.expect_tok(&Token::LBracket)?;
1487
1488 let var = match self.peek().clone() {
1497 Token::Ident(s) if matches!(self.peek2(), Token::Colon) => {
1498 self.advance();
1500 s
1501 }
1502 Token::Ident(s) if matches!(self.peek2(), Token::RBracket) => {
1503 self.advance();
1505 s
1506 }
1507 Token::Ident(s) if matches!(self.peek2(), Token::RBracket | Token::Star) => {
1508 self.advance();
1512 if matches!(self.peek(), Token::Star) {
1513 return Err(Error::InvalidArgument(
1514 "variable-length paths require a relationship type: \
1515 use [r:R*] not [r*]"
1516 .into(),
1517 ));
1518 }
1519 self.expect_tok(&Token::RBracket)?;
1520 let dir = if incoming {
1522 if matches!(self.peek(), Token::Dash) {
1523 self.advance();
1524 } else {
1525 return Err(Error::InvalidArgument(format!(
1526 "expected '-' after ']' for incoming relationship, got {:?}",
1527 self.peek()
1528 )));
1529 }
1530 EdgeDir::Incoming
1531 } else if matches!(self.peek(), Token::Arrow) {
1532 self.advance();
1533 EdgeDir::Outgoing
1534 } else if matches!(self.peek(), Token::Dash) {
1535 self.advance();
1536 EdgeDir::Both
1537 } else {
1538 return Err(Error::InvalidArgument(format!(
1539 "expected '->' or '-' after ']' for outgoing/undirected \
1540 relationship, got {:?}",
1541 self.peek()
1542 )));
1543 };
1544 return Ok(RelPattern {
1545 var: s,
1546 rel_type: String::new(),
1547 dir,
1548 min_hops: None,
1549 max_hops: None,
1550 props: vec![],
1551 });
1552 }
1553 _ => String::new(),
1554 };
1555
1556 let rel_type = if matches!(self.peek(), Token::Colon) {
1558 self.advance(); self.expect_label_or_type()?
1560 } else if matches!(self.peek(), Token::Star) {
1561 return Err(Error::InvalidArgument(
1562 "variable-length paths require a relationship type: use [:R*] not [*]".into(),
1563 ));
1564 } else if matches!(self.peek(), Token::RBracket) {
1565 let rel_type = String::new();
1567 self.expect_tok(&Token::RBracket)?;
1569 let dir = if incoming {
1570 if matches!(self.peek(), Token::Dash) {
1571 self.advance();
1572 } else {
1573 return Err(Error::InvalidArgument(format!(
1574 "expected '-' after ']' for incoming relationship, got {:?}",
1575 self.peek()
1576 )));
1577 }
1578 EdgeDir::Incoming
1579 } else if matches!(self.peek(), Token::Arrow) {
1580 self.advance();
1581 EdgeDir::Outgoing
1582 } else if matches!(self.peek(), Token::Dash) {
1583 self.advance();
1584 EdgeDir::Both
1585 } else {
1586 return Err(Error::InvalidArgument(format!(
1587 "expected '->' or '-' after ']' for outgoing/undirected relationship, got {:?}",
1588 self.peek()
1589 )));
1590 };
1591 return Ok(RelPattern {
1592 var,
1593 rel_type,
1594 dir,
1595 min_hops: None,
1596 max_hops: None,
1597 props: vec![],
1598 });
1599 } else {
1600 String::new()
1602 };
1603
1604 let rel_props: Vec<PropEntry> = if matches!(self.peek(), Token::LBrace) {
1607 self.parse_prop_map()?
1608 } else {
1609 vec![]
1610 };
1611
1612 let (min_hops, max_hops) = if matches!(self.peek(), Token::Star) {
1619 self.advance(); if matches!(self.peek(), Token::DotDot) {
1621 self.advance(); let max = match self.advance().clone() {
1624 Token::Integer(n) if n >= 0 => n as u32,
1625 other => {
1626 return Err(Error::InvalidArgument(format!(
1627 "expected integer after '..', got {:?}",
1628 other
1629 )))
1630 }
1631 };
1632 (Some(1u32), Some(max))
1633 } else if let Token::Integer(n) = self.peek().clone() {
1634 let first = n as u32;
1635 self.advance(); if matches!(self.peek(), Token::DotDot) {
1637 self.advance(); if let Token::Integer(m) = self.peek().clone() {
1639 let second = m as u32;
1640 self.advance(); (Some(first), Some(second))
1643 } else {
1644 (Some(first), None)
1646 }
1647 } else {
1648 (Some(first), Some(first))
1650 }
1651 } else {
1652 (Some(1u32), None)
1654 }
1655 } else {
1656 (None, None)
1657 };
1658
1659 self.expect_tok(&Token::RBracket)?;
1660
1661 let dir = if incoming {
1663 if matches!(self.peek(), Token::Dash) {
1665 self.advance();
1666 } else {
1667 return Err(Error::InvalidArgument(format!(
1668 "expected '-' after ']' for incoming relationship, got {:?}",
1669 self.peek()
1670 )));
1671 }
1672 EdgeDir::Incoming
1673 } else {
1674 if matches!(self.peek(), Token::Arrow) {
1676 self.advance();
1677 EdgeDir::Outgoing
1678 } else if matches!(self.peek(), Token::Dash) {
1679 self.advance();
1680 EdgeDir::Both
1681 } else {
1682 return Err(Error::InvalidArgument(format!(
1683 "expected '->' or '-' after ']' for outgoing/undirected relationship, got {:?}",
1684 self.peek()
1685 )));
1686 }
1687 };
1688
1689 Ok(RelPattern {
1690 var,
1691 rel_type,
1692 dir,
1693 min_hops,
1694 max_hops,
1695 props: rel_props,
1696 })
1697 }
1698
1699 fn parse_prop_map(&mut self) -> Result<Vec<PropEntry>> {
1702 self.expect_tok(&Token::LBrace)?;
1703 let mut entries = Vec::new();
1704
1705 if matches!(self.peek(), Token::RBrace) {
1706 self.advance();
1707 return Ok(entries);
1708 }
1709
1710 loop {
1711 let key = self.advance_as_prop_name()?;
1714 self.expect_tok(&Token::Colon)?;
1715 let value = self.parse_expr()?;
1716 entries.push(PropEntry { key, value });
1717
1718 if matches!(self.peek(), Token::Comma) {
1719 self.advance();
1720 } else {
1721 break;
1722 }
1723 }
1724
1725 self.expect_tok(&Token::RBrace)?;
1726 Ok(entries)
1727 }
1728
1729 fn parse_literal(&mut self) -> Result<Literal> {
1732 match self.advance().clone() {
1733 Token::Integer(n) => Ok(Literal::Int(n)),
1734 Token::Float(f) => Ok(Literal::Float(f)),
1735 Token::Str(s) => Ok(Literal::String(s)),
1736 Token::Param(p) => Ok(Literal::Param(p)),
1737 Token::Null => Ok(Literal::Null),
1738 Token::True => Ok(Literal::Bool(true)),
1739 Token::False => Ok(Literal::Bool(false)),
1740 other => Err(Error::InvalidArgument(format!(
1741 "expected literal, got {:?}",
1742 other
1743 ))),
1744 }
1745 }
1746
1747 fn parse_expr(&mut self) -> Result<Expr> {
1750 self.parse_or_expr()
1751 }
1752
1753 fn parse_or_expr(&mut self) -> Result<Expr> {
1754 let mut left = self.parse_and_expr()?;
1755 while matches!(self.peek(), Token::Or) {
1756 self.advance();
1757 let right = self.parse_and_expr()?;
1758 left = Expr::Or(Box::new(left), Box::new(right));
1759 }
1760 Ok(left)
1761 }
1762
1763 fn parse_and_expr(&mut self) -> Result<Expr> {
1764 let mut left = self.parse_not_expr()?;
1765 while matches!(self.peek(), Token::And) {
1766 self.advance();
1767 let right = self.parse_not_expr()?;
1768 left = Expr::And(Box::new(left), Box::new(right));
1769 }
1770 Ok(left)
1771 }
1772
1773 fn parse_not_expr(&mut self) -> Result<Expr> {
1774 if matches!(self.peek(), Token::Not) {
1775 self.advance();
1776 if matches!(self.peek(), Token::LParen) {
1778 let saved_pos = self.pos;
1780 match self.parse_path_pattern() {
1781 Ok(path) => return Ok(Expr::NotExists(Box::new(ExistsPattern { path }))),
1782 Err(_) => {
1783 self.pos = saved_pos; }
1786 }
1787 }
1788 let inner = self.parse_comparison()?;
1789 return Ok(Expr::Not(Box::new(inner)));
1790 }
1791 self.parse_comparison()
1792 }
1793
1794 fn parse_comparison(&mut self) -> Result<Expr> {
1795 let left = self.parse_additive()?;
1796
1797 if matches!(self.peek(), Token::Is) {
1799 self.advance(); if matches!(self.peek(), Token::Not) {
1801 self.advance(); match self.peek().clone() {
1804 Token::Null => {
1805 self.advance();
1806 return Ok(Expr::IsNotNull(Box::new(left)));
1807 }
1808 other => {
1809 return Err(Error::InvalidArgument(format!(
1810 "expected NULL after IS NOT, got {:?}",
1811 other
1812 )));
1813 }
1814 }
1815 } else {
1816 match self.peek().clone() {
1818 Token::Null => {
1819 self.advance();
1820 return Ok(Expr::IsNull(Box::new(left)));
1821 }
1822 other => {
1823 return Err(Error::InvalidArgument(format!(
1824 "expected NULL after IS, got {:?}",
1825 other
1826 )));
1827 }
1828 }
1829 }
1830 }
1831
1832 if matches!(self.peek(), Token::In) {
1834 self.advance(); self.expect_tok(&Token::LBracket)?;
1836 let list = self.parse_in_list()?;
1837 return Ok(Expr::InList {
1838 expr: Box::new(left),
1839 list,
1840 negated: false,
1841 });
1842 }
1843
1844 let op = match self.peek().clone() {
1845 Token::Eq => BinOpKind::Eq,
1846 Token::Neq => BinOpKind::Neq,
1847 Token::Lt => BinOpKind::Lt,
1848 Token::Le => BinOpKind::Le,
1849 Token::Gt => BinOpKind::Gt,
1850 Token::Ge => BinOpKind::Ge,
1851 Token::Contains => BinOpKind::Contains,
1852 Token::StartsWith => {
1853 self.advance();
1854 match self.peek().clone() {
1856 Token::With | Token::Ident(_) => {
1857 self.advance();
1858 }
1859 other => {
1860 return Err(Error::InvalidArgument(format!(
1861 "expected WITH after STARTS, got {:?}",
1862 other
1863 )));
1864 }
1865 }
1866 let right = self.parse_atom()?;
1867 return Ok(Expr::BinOp {
1868 left: Box::new(left),
1869 op: BinOpKind::StartsWith,
1870 right: Box::new(right),
1871 });
1872 }
1873 Token::EndsWith => {
1874 self.advance();
1875 match self.peek().clone() {
1877 Token::With | Token::Ident(_) => {
1878 self.advance();
1879 }
1880 other => {
1881 return Err(Error::InvalidArgument(format!(
1882 "expected WITH after ENDS, got {:?}",
1883 other
1884 )));
1885 }
1886 }
1887 let right = self.parse_atom()?;
1888 return Ok(Expr::BinOp {
1889 left: Box::new(left),
1890 op: BinOpKind::EndsWith,
1891 right: Box::new(right),
1892 });
1893 }
1894 _ => return Ok(left),
1895 };
1896 self.advance();
1897 let right = self.parse_additive()?;
1898 Ok(Expr::BinOp {
1899 left: Box::new(left),
1900 op,
1901 right: Box::new(right),
1902 })
1903 }
1904
1905 fn parse_additive(&mut self) -> Result<Expr> {
1907 let mut left = self.parse_multiplicative()?;
1908 loop {
1909 let op = match self.peek() {
1910 Token::Plus => BinOpKind::Add,
1911 Token::Dash => BinOpKind::Sub,
1912 _ => break,
1913 };
1914 self.advance();
1915 let right = self.parse_multiplicative()?;
1916 left = Expr::BinOp {
1917 left: Box::new(left),
1918 op,
1919 right: Box::new(right),
1920 };
1921 }
1922 Ok(left)
1923 }
1924
1925 fn parse_multiplicative(&mut self) -> Result<Expr> {
1927 let mut left = self.parse_atom()?;
1928 loop {
1929 let op = match self.peek() {
1930 Token::Star => BinOpKind::Mul,
1931 Token::Slash => BinOpKind::Div,
1932 Token::Percent => BinOpKind::Mod,
1933 _ => break,
1934 };
1935 self.advance();
1936 let right = self.parse_atom()?;
1937 left = Expr::BinOp {
1938 left: Box::new(left),
1939 op,
1940 right: Box::new(right),
1941 };
1942 }
1943 Ok(left)
1944 }
1945
1946 fn parse_in_list(&mut self) -> Result<Vec<Expr>> {
1949 let mut items = Vec::new();
1950 if matches!(self.peek(), Token::RBracket) {
1951 self.advance(); return Ok(items); }
1954 loop {
1955 items.push(self.parse_atom()?);
1956 match self.peek().clone() {
1957 Token::Comma => {
1958 self.advance();
1959 }
1960 Token::RBracket => {
1961 self.advance();
1962 break;
1963 }
1964 other => {
1965 return Err(Error::InvalidArgument(format!(
1966 "expected ',' or ']' in IN list, got {:?}",
1967 other
1968 )));
1969 }
1970 }
1971 }
1972 Ok(items)
1973 }
1974
1975 fn parse_atom(&mut self) -> Result<Expr> {
1976 match self.peek().clone() {
1977 Token::Ident(var) => {
1978 let next2 = self.peek2().clone();
1980 if matches!(next2, Token::Dot) {
1981 self.advance(); self.advance(); let prop = self.advance_as_prop_name()?;
1985 Ok(Expr::PropAccess { var, prop })
1986 } else if matches!(next2, Token::LParen) {
1987 if var.to_lowercase() == "shortestpath"
1989 || var.to_lowercase() == "allshortestpaths"
1990 {
1991 self.advance(); return self.parse_shortest_path_fn();
1993 }
1994 self.advance(); self.advance(); let mut args = Vec::new();
1998 if !matches!(self.peek(), Token::RParen) {
1999 loop {
2000 args.push(self.parse_expr()?);
2001 if matches!(self.peek(), Token::Comma) {
2002 self.advance();
2003 } else {
2004 break;
2005 }
2006 }
2007 }
2008 self.expect_tok(&Token::RParen)?;
2009 Ok(Expr::FnCall { name: var, args })
2010 } else {
2011 self.advance();
2012 Ok(Expr::Var(var))
2013 }
2014 }
2015 Token::Count => {
2016 self.advance();
2017 self.expect_tok(&Token::LParen)?;
2018 if self.peek() == &Token::Star {
2019 self.advance();
2021 self.expect_tok(&Token::RParen)?;
2022 Ok(Expr::CountStar)
2023 } else {
2024 let arg = self.parse_expr()?;
2026 self.expect_tok(&Token::RParen)?;
2027 Ok(Expr::FnCall {
2028 name: "count".to_string(),
2029 args: vec![arg],
2030 })
2031 }
2032 }
2033 Token::Integer(_)
2034 | Token::Float(_)
2035 | Token::Str(_)
2036 | Token::Param(_)
2037 | Token::Null
2038 | Token::True
2039 | Token::False => {
2040 let lit = self.parse_literal()?;
2041 Ok(Expr::Literal(lit))
2042 }
2043 Token::LParen => {
2044 self.advance();
2045 let e = self.parse_expr()?;
2046 self.expect_tok(&Token::RParen)?;
2047 Ok(e)
2048 }
2049 Token::LBracket => self.parse_list_literal(),
2051 Token::Any | Token::All | Token::NoneKw | Token::Single => {
2053 let kind = match self.advance().clone() {
2054 Token::Any => ListPredicateKind::Any,
2055 Token::All => ListPredicateKind::All,
2056 Token::NoneKw => ListPredicateKind::None,
2057 Token::Single => ListPredicateKind::Single,
2058 _ => unreachable!(),
2059 };
2060 self.expect_tok(&Token::LParen)?;
2061 let variable = self.expect_ident()?;
2062 self.expect_tok(&Token::In)?;
2063 let list_expr = self.parse_expr()?;
2064 self.expect_tok(&Token::Where)?;
2065 let predicate = self.parse_expr()?;
2066 self.expect_tok(&Token::RParen)?;
2067 Ok(Expr::ListPredicate {
2068 kind,
2069 variable,
2070 list_expr: Box::new(list_expr),
2071 predicate: Box::new(predicate),
2072 })
2073 }
2074 Token::Exists => {
2076 self.advance(); self.expect_tok(&Token::LBrace)?;
2078 let path = self.parse_path_pattern()?;
2079 self.expect_tok(&Token::RBrace)?;
2080 Ok(Expr::ExistsSubquery(Box::new(ExistsPattern { path })))
2081 }
2082 Token::Case => {
2084 self.advance(); let mut branches: Vec<(Expr, Expr)> = Vec::new();
2086 let mut else_expr: Option<Box<Expr>> = None;
2087 let mut seen_when = false;
2088 let mut seen_else = false;
2089 loop {
2090 match self.peek().clone() {
2091 Token::When => {
2092 if seen_else {
2093 return Err(Error::InvalidArgument(
2094 "WHEN cannot follow ELSE in CASE expression".to_string(),
2095 ));
2096 }
2097 self.advance(); let cond = self.parse_expr()?;
2099 self.expect_tok(&Token::Then)?;
2100 let val = self.parse_expr()?;
2101 branches.push((cond, val));
2102 seen_when = true;
2103 }
2104 Token::Else => {
2105 if !seen_when {
2106 return Err(Error::InvalidArgument(
2107 "ELSE requires at least one WHEN branch in CASE expression"
2108 .to_string(),
2109 ));
2110 }
2111 if seen_else {
2112 return Err(Error::InvalidArgument(
2113 "duplicate ELSE in CASE expression".to_string(),
2114 ));
2115 }
2116 self.advance(); else_expr = Some(Box::new(self.parse_expr()?));
2118 seen_else = true;
2119 }
2120 Token::End => {
2121 if !seen_when {
2122 return Err(Error::InvalidArgument(
2123 "CASE expression requires at least one WHEN branch".to_string(),
2124 ));
2125 }
2126 self.advance(); break;
2128 }
2129 other => {
2130 return Err(Error::InvalidArgument(format!(
2131 "expected WHEN, ELSE, or END in CASE expression, got {:?}",
2132 other
2133 )));
2134 }
2135 }
2136 }
2137 Ok(Expr::CaseWhen {
2138 branches,
2139 else_expr,
2140 })
2141 }
2142 Token::Dash => {
2144 self.advance();
2145 let inner = self.parse_atom()?;
2146 match inner {
2147 Expr::Literal(Literal::Int(n)) => Ok(Expr::Literal(Literal::Int(-n))),
2148 Expr::Literal(Literal::Float(f)) => Ok(Expr::Literal(Literal::Float(-f))),
2149 other => Ok(Expr::FnCall {
2153 name: "_neg".into(),
2154 args: vec![other],
2155 }),
2156 }
2157 }
2158 other => Err(Error::InvalidArgument(format!(
2159 "unexpected token in expression: {:?}",
2160 other
2161 ))),
2162 }
2163 }
2164
2165 fn parse_shortest_path_fn(&mut self) -> Result<Expr> {
2167 self.expect_tok(&Token::LParen)?;
2168 let path = self.parse_path_pattern()?;
2169 self.expect_tok(&Token::RParen)?;
2170
2171 if path.nodes.len() != 2 || path.rels.len() != 1 {
2172 return Err(Error::InvalidArgument(
2173 "shortestPath() requires exactly one relationship pattern".into(),
2174 ));
2175 }
2176 let src_node = &path.nodes[0];
2177 let dst_node = &path.nodes[1];
2178 let rel = &path.rels[0];
2179
2180 Ok(Expr::ShortestPath(Box::new(ShortestPathExpr {
2181 src_var: src_node.var.clone(),
2182 src_label: src_node.labels.first().cloned().unwrap_or_default(),
2183 src_props: src_node.props.clone(),
2184 dst_var: dst_node.var.clone(),
2185 dst_label: dst_node.labels.first().cloned().unwrap_or_default(),
2186 dst_props: dst_node.props.clone(),
2187 rel_type: rel.rel_type.clone(),
2188 })))
2189 }
2190
2191 fn parse_return_items(&mut self) -> Result<Vec<ReturnItem>> {
2194 if matches!(self.peek(), Token::Star) {
2195 self.advance();
2196 return Ok(vec![ReturnItem {
2197 expr: Expr::Var("*".into()),
2198 alias: None,
2199 }]);
2200 }
2201
2202 let mut items = Vec::new();
2203 loop {
2204 let expr = self.parse_expr()?;
2205 let alias = if matches!(self.peek(), Token::As) {
2206 self.advance();
2207 Some(self.expect_ident()?)
2208 } else {
2209 None
2210 };
2211 items.push(ReturnItem { expr, alias });
2212 if matches!(self.peek(), Token::Comma) {
2213 self.advance();
2214 } else {
2215 break;
2216 }
2217 }
2218 Ok(items)
2219 }
2220
2221 fn parse_order_by_items(&mut self) -> Result<Vec<(Expr, SortDir)>> {
2224 let mut items = Vec::new();
2225 loop {
2226 let expr = self.parse_expr()?;
2227 let dir = match self.peek().clone() {
2228 Token::Desc => {
2229 self.advance();
2230 SortDir::Desc
2231 }
2232 Token::Asc => {
2233 self.advance();
2234 SortDir::Asc
2235 }
2236 _ => SortDir::Asc,
2237 };
2238 items.push((expr, dir));
2239 if matches!(self.peek(), Token::Comma) {
2240 self.advance();
2241 } else {
2242 break;
2243 }
2244 }
2245 Ok(items)
2246 }
2247
2248 fn parse_call(&mut self) -> Result<Statement> {
2258 self.expect_tok(&Token::Call)?;
2259
2260 let mut proc_name = self.advance_as_prop_name()?;
2265 while matches!(self.peek(), Token::Dot) {
2266 self.advance(); let part = self.advance_as_prop_name()?;
2268 proc_name.push('.');
2269 proc_name.push_str(&part);
2270 }
2271
2272 self.expect_tok(&Token::LParen)?;
2274 let mut args = Vec::new();
2275 if !matches!(self.peek(), Token::RParen) {
2276 loop {
2277 args.push(self.parse_atom()?);
2278 if matches!(self.peek(), Token::Comma) {
2279 self.advance();
2280 } else {
2281 break;
2282 }
2283 }
2284 }
2285 self.expect_tok(&Token::RParen)?;
2286
2287 let yield_columns = if matches!(self.peek(), Token::Yield) {
2289 self.advance(); let mut cols = Vec::new();
2291 loop {
2292 cols.push(self.expect_ident()?);
2293 if matches!(self.peek(), Token::Comma) {
2294 self.advance();
2295 } else {
2296 break;
2297 }
2298 }
2299 cols
2300 } else {
2301 vec![]
2302 };
2303
2304 let return_clause = if matches!(self.peek(), Token::Return) {
2306 self.advance(); let distinct = if matches!(self.peek(), Token::Distinct) {
2308 self.advance();
2309 true
2310 } else {
2311 false
2312 };
2313 let _ = distinct; let items = self.parse_return_items()?;
2315 Some(ReturnClause { items })
2316 } else {
2317 None
2318 };
2319
2320 Ok(Statement::Call(CallStatement {
2321 procedure: proc_name,
2322 args,
2323 yield_columns,
2324 return_clause,
2325 }))
2326 }
2327}
2328
2329#[cfg(test)]
2330mod tests {
2331 use super::*;
2332 use crate::ast::Statement;
2333
2334 #[test]
2335 fn parse_checkpoint_smoke() {
2336 assert!(matches!(parse("CHECKPOINT"), Ok(Statement::Checkpoint)));
2337 }
2338
2339 #[test]
2340 fn parse_optimize_smoke() {
2341 assert!(matches!(parse("OPTIMIZE"), Ok(Statement::Optimize)));
2342 }
2343
2344 #[test]
2345 fn parse_empty_fails() {
2346 assert!(parse("").is_err());
2347 }
2348
2349 #[test]
2350 fn parse_optional_match_ok() {
2351 let stmt = parse("OPTIONAL MATCH (n:Person) RETURN n.name").unwrap();
2353 assert!(matches!(stmt, Statement::OptionalMatch(_)));
2354 }
2355
2356 #[test]
2357 fn parse_optional_match_missing_return_fails() {
2358 assert!(parse("OPTIONAL MATCH (n:Person)").is_err());
2359 }
2360
2361 #[test]
2362 fn parse_create_node() {
2363 let stmt = parse("CREATE (n:Person {name: \"Alice\"})").unwrap();
2364 assert!(matches!(stmt, Statement::Create(_)));
2365 }
2366
2367 #[test]
2368 fn parse_match_return() {
2369 let stmt = parse("MATCH (n:Person) RETURN n.name").unwrap();
2370 assert!(matches!(stmt, Statement::Match(_)));
2371 }
2372}