1use super::ast::*;
4use super::{ParseError, Parser};
5use crate::lexer::Token;
6
7impl<'a> Parser<'a> {
8 pub fn parse_pattern(&mut self) -> Result<Pattern, ParseError> {
10 let mut chains = Vec::new();
11 chains.push(self.parse_pattern_chain()?);
12 while self.eat(&Token::Comma) {
13 chains.push(self.parse_pattern_chain()?);
14 }
15 Ok(Pattern { chains })
16 }
17
18 fn parse_pattern_chain(&mut self) -> Result<PatternChain, ParseError> {
20 let mut elements = Vec::new();
21 elements.push(PatternElement::Node(self.parse_node_pattern()?));
22
23 loop {
24 match self.peek() {
25 Some(Token::Minus) => {
27 let rel = self.parse_relationship_from_minus()?;
28 elements.push(PatternElement::Relationship(rel));
29 elements.push(PatternElement::Node(self.parse_node_pattern()?));
30 }
31 Some(Token::ArrowLeft) => {
33 let rel = self.parse_relationship_incoming()?;
34 elements.push(PatternElement::Relationship(rel));
35 elements.push(PatternElement::Node(self.parse_node_pattern()?));
36 }
37 Some(Token::DoubleDash) => {
39 self.advance(); elements.push(PatternElement::Relationship(RelationshipPattern {
41 variable: None,
42 rel_types: Vec::new(),
43 direction: RelDirection::Undirected,
44 properties: None,
45 min_hops: None,
46 max_hops: None,
47 }));
48 elements.push(PatternElement::Node(self.parse_node_pattern()?));
49 }
50 _ => break,
51 }
52 }
53
54 Ok(PatternChain { elements })
55 }
56
57 pub fn parse_node_pattern(&mut self) -> Result<NodePattern, ParseError> {
60 self.expect(&Token::LParen)?;
61
62 let mut variable = None;
63 let mut labels = Vec::new();
64 let mut properties = None;
65
66 if let Some(Token::Ident(_) | Token::BacktickIdent(_)) = self.peek() {
69 variable = Some(self.expect_ident()?);
70 }
71
72 while self.eat(&Token::Colon) {
74 labels.push(self.expect_ident()?);
75 }
76
77 if self.check(&Token::LBrace) {
79 properties = Some(self.parse_map_literal()?);
80 }
81
82 self.expect(&Token::RParen)?;
83
84 Ok(NodePattern {
85 variable,
86 labels,
87 properties,
88 })
89 }
90
91 pub fn parse_map_literal(&mut self) -> Result<MapLiteral, ParseError> {
93 self.expect(&Token::LBrace)?;
94 let mut entries = Vec::new();
95
96 if !self.check(&Token::RBrace) {
97 let key = self.expect_ident()?;
98 self.expect(&Token::Colon)?;
99 let value = self.parse_expression()?;
100 entries.push((key, value));
101
102 while self.eat(&Token::Comma) {
103 let key = self.expect_ident()?;
104 self.expect(&Token::Colon)?;
105 let value = self.parse_expression()?;
106 entries.push((key, value));
107 }
108 }
109
110 self.expect(&Token::RBrace)?;
111 Ok(entries)
112 }
113
114 fn parse_relationship_from_minus(&mut self) -> Result<RelationshipPattern, ParseError> {
116 self.expect(&Token::Minus)?;
117
118 self.expect(&Token::LBracket)?;
120
121 let content = self.parse_relationship_content()?;
123
124 self.expect(&Token::RBracket)?;
125
126 let direction = if self.eat(&Token::ArrowRight) {
128 RelDirection::Outgoing
129 } else if self.eat(&Token::Minus) {
130 RelDirection::Undirected
131 } else {
132 return Err(self.error("expected -> or - after relationship bracket"));
133 };
134
135 Ok(RelationshipPattern {
136 variable: content.variable,
137 rel_types: content.rel_types,
138 direction,
139 properties: content.properties,
140 min_hops: content.min_hops,
141 max_hops: content.max_hops,
142 })
143 }
144
145 fn parse_relationship_incoming(&mut self) -> Result<RelationshipPattern, ParseError> {
147 self.expect(&Token::ArrowLeft)?;
149
150 self.expect(&Token::LBracket)?;
151 let content = self.parse_relationship_content()?;
152 self.expect(&Token::RBracket)?;
153
154 self.expect(&Token::Minus)?;
156
157 Ok(RelationshipPattern {
158 variable: content.variable,
159 rel_types: content.rel_types,
160 direction: RelDirection::Incoming,
161 properties: content.properties,
162 min_hops: content.min_hops,
163 max_hops: content.max_hops,
164 })
165 }
166
167 fn parse_relationship_content(&mut self) -> Result<RelContentResult, ParseError> {
169 let mut variable = None;
170 let mut rel_types = Vec::new();
171 let mut properties = None;
172 let mut min_hops = None;
173 let mut max_hops = None;
174
175 if self.check(&Token::Star) {
177 let (mn, mx) = self.parse_var_length_spec()?;
178 min_hops = Some(mn);
179 max_hops = mx;
180
181 if self.check(&Token::LBrace) {
183 properties = Some(self.parse_map_literal()?);
184 }
185 return Ok(RelContentResult {
186 variable,
187 rel_types,
188 properties,
189 min_hops,
190 max_hops,
191 });
192 }
193
194 if let Some(Token::Ident(_) | Token::BacktickIdent(_)) = self.peek() {
196 variable = Some(self.expect_ident()?);
197 }
198
199 if self.check(&Token::Star) {
201 let (mn, mx) = self.parse_var_length_spec()?;
202 min_hops = Some(mn);
203 max_hops = mx;
204
205 if self.check(&Token::LBrace) {
206 properties = Some(self.parse_map_literal()?);
207 }
208 return Ok(RelContentResult {
209 variable,
210 rel_types,
211 properties,
212 min_hops,
213 max_hops,
214 });
215 }
216
217 if self.eat(&Token::Colon) {
219 rel_types.push(self.expect_ident()?);
220 while self.eat(&Token::Pipe) {
221 rel_types.push(self.expect_ident()?);
222 }
223 }
224
225 if self.check(&Token::Star) {
227 let (mn, mx) = self.parse_var_length_spec()?;
228 min_hops = Some(mn);
229 max_hops = mx;
230 }
231
232 if self.check(&Token::LBrace) {
234 properties = Some(self.parse_map_literal()?);
235 }
236
237 Ok(RelContentResult {
238 variable,
239 rel_types,
240 properties,
241 min_hops,
242 max_hops,
243 })
244 }
245
246 fn parse_var_length_spec(&mut self) -> Result<(u32, Option<u32>), ParseError> {
249 self.expect(&Token::Star)?;
250
251 if self.eat(&Token::DoubleDot) {
253 if let Some(Token::Integer(n)) = self.peek() {
255 let max = Self::int_to_u32(*n, self)?;
256 self.advance();
257 return Ok((1, Some(max)));
258 }
259 return Ok((1, None));
261 }
262
263 if let Some(Token::Integer(n)) = self.peek() {
265 let first = Self::int_to_u32(*n, self)?;
266 self.advance();
267
268 if self.eat(&Token::DoubleDot) {
270 if let Some(Token::Integer(m)) = self.peek() {
271 let second = Self::int_to_u32(*m, self)?;
272 self.advance();
273 return Ok((first, Some(second)));
274 }
275 return Ok((first, None));
277 }
278
279 return Ok((first, Some(first)));
281 }
282
283 Ok((1, None))
285 }
286
287 fn int_to_u32(n: i64, parser: &Self) -> Result<u32, ParseError> {
289 if n < 0 {
290 return Err(parser.error("hop count must be non-negative"));
291 }
292 Ok(n as u32)
293 }
294}
295
296struct RelContentResult {
298 variable: Option<String>,
299 rel_types: Vec<String>,
300 properties: Option<MapLiteral>,
301 min_hops: Option<u32>,
302 max_hops: Option<u32>,
303}
304
305#[cfg(test)]
310mod tests {
311 use super::*;
312 use crate::lexer::lex;
313
314 fn parse_pattern_str(input: &str) -> Result<Pattern, ParseError> {
316 let tokens = lex(input).expect("lexing should succeed");
317 let mut parser = Parser::new(&tokens, input);
318 parser.parse_pattern()
319 }
320
321 fn parse_node(input: &str) -> Result<NodePattern, ParseError> {
323 let tokens = lex(input).expect("lexing should succeed");
324 let mut parser = Parser::new(&tokens, input);
325 parser.parse_node_pattern()
326 }
327
328 #[test]
332 fn pattern_single_node_with_label() {
333 let node = parse_node("(n:Person)").expect("should parse");
334 assert_eq!(
335 node,
336 NodePattern {
337 variable: Some("n".to_string()),
338 labels: vec!["Person".to_string()],
339 properties: None,
340 }
341 );
342 }
343
344 #[test]
346 fn pattern_node_no_label() {
347 let node = parse_node("(n)").expect("should parse");
348 assert_eq!(
349 node,
350 NodePattern {
351 variable: Some("n".to_string()),
352 labels: vec![],
353 properties: None,
354 }
355 );
356 }
357
358 #[test]
360 fn pattern_empty_node() {
361 let node = parse_node("()").expect("should parse");
362 assert_eq!(
363 node,
364 NodePattern {
365 variable: None,
366 labels: vec![],
367 properties: None,
368 }
369 );
370 }
371
372 #[test]
374 fn pattern_node_with_properties() {
375 let node = parse_node("(n:Person {name: 'Alice'})").expect("should parse");
376 assert_eq!(
377 node,
378 NodePattern {
379 variable: Some("n".to_string()),
380 labels: vec!["Person".to_string()],
381 properties: Some(vec![(
382 "name".to_string(),
383 Expression::Literal(Literal::String("Alice".to_string())),
384 )]),
385 }
386 );
387 }
388
389 #[test]
391 fn pattern_node_multiple_labels() {
392 let node = parse_node("(n:Person:Employee)").expect("should parse");
393 assert_eq!(
394 node,
395 NodePattern {
396 variable: Some("n".to_string()),
397 labels: vec!["Person".to_string(), "Employee".to_string()],
398 properties: None,
399 }
400 );
401 }
402
403 #[test]
405 fn pattern_node_multiple_properties() {
406 let node = parse_node("(n:Person {name: 'Alice', age: 30})").expect("should parse");
407 assert_eq!(
408 node,
409 NodePattern {
410 variable: Some("n".to_string()),
411 labels: vec!["Person".to_string()],
412 properties: Some(vec![
413 (
414 "name".to_string(),
415 Expression::Literal(Literal::String("Alice".to_string())),
416 ),
417 ("age".to_string(), Expression::Literal(Literal::Integer(30)),),
418 ]),
419 }
420 );
421 }
422
423 #[test]
425 fn pattern_node_label_no_variable() {
426 let node = parse_node("(:Person)").expect("should parse");
427 assert_eq!(
428 node,
429 NodePattern {
430 variable: None,
431 labels: vec!["Person".to_string()],
432 properties: None,
433 }
434 );
435 }
436
437 #[test]
439 fn pattern_outgoing_relationship() {
440 let pattern = parse_pattern_str("(a)-[:KNOWS]->(b)").expect("should parse");
441 assert_eq!(pattern.chains.len(), 1);
442 let chain = &pattern.chains[0];
443 assert_eq!(chain.elements.len(), 3);
444
445 assert_eq!(
446 chain.elements[0],
447 PatternElement::Node(NodePattern {
448 variable: Some("a".to_string()),
449 labels: vec![],
450 properties: None,
451 })
452 );
453 assert_eq!(
454 chain.elements[1],
455 PatternElement::Relationship(RelationshipPattern {
456 variable: None,
457 rel_types: vec!["KNOWS".to_string()],
458 direction: RelDirection::Outgoing,
459 properties: None,
460 min_hops: None,
461 max_hops: None,
462 })
463 );
464 assert_eq!(
465 chain.elements[2],
466 PatternElement::Node(NodePattern {
467 variable: Some("b".to_string()),
468 labels: vec![],
469 properties: None,
470 })
471 );
472 }
473
474 #[test]
476 fn pattern_incoming_relationship() {
477 let pattern = parse_pattern_str("(a)<-[:KNOWS]-(b)").expect("should parse");
478 let chain = &pattern.chains[0];
479 assert_eq!(
480 chain.elements[1],
481 PatternElement::Relationship(RelationshipPattern {
482 variable: None,
483 rel_types: vec!["KNOWS".to_string()],
484 direction: RelDirection::Incoming,
485 properties: None,
486 min_hops: None,
487 max_hops: None,
488 })
489 );
490 }
491
492 #[test]
494 fn pattern_undirected_relationship() {
495 let pattern = parse_pattern_str("(a)-[:KNOWS]-(b)").expect("should parse");
496 let chain = &pattern.chains[0];
497 assert_eq!(
498 chain.elements[1],
499 PatternElement::Relationship(RelationshipPattern {
500 variable: None,
501 rel_types: vec!["KNOWS".to_string()],
502 direction: RelDirection::Undirected,
503 properties: None,
504 min_hops: None,
505 max_hops: None,
506 })
507 );
508 }
509
510 #[test]
512 fn pattern_undirected_no_brackets() {
513 let pattern = parse_pattern_str("(a)--(b)").expect("should parse");
514 let chain = &pattern.chains[0];
515 assert_eq!(
516 chain.elements[1],
517 PatternElement::Relationship(RelationshipPattern {
518 variable: None,
519 rel_types: vec![],
520 direction: RelDirection::Undirected,
521 properties: None,
522 min_hops: None,
523 max_hops: None,
524 })
525 );
526 }
527
528 #[test]
530 fn pattern_relationship_with_variable() {
531 let pattern = parse_pattern_str("(a)-[r:KNOWS]->(b)").expect("should parse");
532 let chain = &pattern.chains[0];
533 assert_eq!(
534 chain.elements[1],
535 PatternElement::Relationship(RelationshipPattern {
536 variable: Some("r".to_string()),
537 rel_types: vec!["KNOWS".to_string()],
538 direction: RelDirection::Outgoing,
539 properties: None,
540 min_hops: None,
541 max_hops: None,
542 })
543 );
544 }
545
546 #[test]
548 fn pattern_relationship_with_properties() {
549 let pattern = parse_pattern_str("(a)-[r:KNOWS {since: 2020}]->(b)").expect("should parse");
550 let chain = &pattern.chains[0];
551 assert_eq!(
552 chain.elements[1],
553 PatternElement::Relationship(RelationshipPattern {
554 variable: Some("r".to_string()),
555 rel_types: vec!["KNOWS".to_string()],
556 direction: RelDirection::Outgoing,
557 properties: Some(vec![(
558 "since".to_string(),
559 Expression::Literal(Literal::Integer(2020)),
560 )]),
561 min_hops: None,
562 max_hops: None,
563 })
564 );
565 }
566
567 #[test]
569 fn pattern_multiple_rel_types() {
570 let pattern = parse_pattern_str("(a)-[:KNOWS|LIKES]->(b)").expect("should parse");
571 let chain = &pattern.chains[0];
572 assert_eq!(
573 chain.elements[1],
574 PatternElement::Relationship(RelationshipPattern {
575 variable: None,
576 rel_types: vec!["KNOWS".to_string(), "LIKES".to_string()],
577 direction: RelDirection::Outgoing,
578 properties: None,
579 min_hops: None,
580 max_hops: None,
581 })
582 );
583 }
584
585 #[test]
587 fn pattern_multi_hop() {
588 let pattern = parse_pattern_str("(a)-[:KNOWS]->(b)-[:KNOWS]->(c)").expect("should parse");
589 let chain = &pattern.chains[0];
590 assert_eq!(chain.elements.len(), 5);
591 assert!(matches!(&chain.elements[0], PatternElement::Node(_)));
593 assert!(matches!(
594 &chain.elements[1],
595 PatternElement::Relationship(_)
596 ));
597 assert!(matches!(&chain.elements[2], PatternElement::Node(_)));
598 assert!(matches!(
599 &chain.elements[3],
600 PatternElement::Relationship(_)
601 ));
602 assert!(matches!(&chain.elements[4], PatternElement::Node(_)));
603 }
604
605 #[test]
607 fn pattern_multiple_chains() {
608 let pattern =
609 parse_pattern_str("(a)-[:KNOWS]->(b), (c)-[:LIKES]->(d)").expect("should parse");
610 assert_eq!(pattern.chains.len(), 2);
611 assert_eq!(pattern.chains[0].elements.len(), 3);
612 assert_eq!(pattern.chains[1].elements.len(), 3);
613 }
614
615 #[test]
619 fn pattern_var_length_star_only() {
620 let pattern = parse_pattern_str("(a)-[*]->(b)").expect("should parse");
621 let chain = &pattern.chains[0];
622 if let PatternElement::Relationship(rel) = &chain.elements[1] {
623 assert_eq!(rel.min_hops, Some(1));
624 assert_eq!(rel.max_hops, None);
625 } else {
626 panic!("expected relationship");
627 }
628 }
629
630 #[test]
632 fn pattern_var_length_exact_hop() {
633 let pattern = parse_pattern_str("(a)-[*3]->(b)").expect("should parse");
634 let chain = &pattern.chains[0];
635 if let PatternElement::Relationship(rel) = &chain.elements[1] {
636 assert_eq!(rel.min_hops, Some(3));
637 assert_eq!(rel.max_hops, Some(3));
638 } else {
639 panic!("expected relationship");
640 }
641 }
642
643 #[test]
645 fn pattern_var_length_range() {
646 let pattern = parse_pattern_str("(a)-[*1..3]->(b)").expect("should parse");
647 let chain = &pattern.chains[0];
648 if let PatternElement::Relationship(rel) = &chain.elements[1] {
649 assert_eq!(rel.min_hops, Some(1));
650 assert_eq!(rel.max_hops, Some(3));
651 } else {
652 panic!("expected relationship");
653 }
654 }
655
656 #[test]
658 fn pattern_var_length_open_end() {
659 let pattern = parse_pattern_str("(a)-[*2..]->(b)").expect("should parse");
660 let chain = &pattern.chains[0];
661 if let PatternElement::Relationship(rel) = &chain.elements[1] {
662 assert_eq!(rel.min_hops, Some(2));
663 assert_eq!(rel.max_hops, None);
664 } else {
665 panic!("expected relationship");
666 }
667 }
668
669 #[test]
671 fn pattern_var_length_open_start() {
672 let pattern = parse_pattern_str("(a)-[*..5]->(b)").expect("should parse");
673 let chain = &pattern.chains[0];
674 if let PatternElement::Relationship(rel) = &chain.elements[1] {
675 assert_eq!(rel.min_hops, Some(1));
676 assert_eq!(rel.max_hops, Some(5));
677 } else {
678 panic!("expected relationship");
679 }
680 }
681
682 #[test]
684 fn pattern_var_length_typed_bounded() {
685 let pattern = parse_pattern_str("(a)-[:KNOWS*2..4]->(b)").expect("should parse");
686 let chain = &pattern.chains[0];
687 if let PatternElement::Relationship(rel) = &chain.elements[1] {
688 assert_eq!(rel.rel_types, vec!["KNOWS".to_string()]);
689 assert_eq!(rel.min_hops, Some(2));
690 assert_eq!(rel.max_hops, Some(4));
691 } else {
692 panic!("expected relationship");
693 }
694 }
695
696 #[test]
698 fn pattern_var_length_variable_typed_bounded() {
699 let pattern = parse_pattern_str("(a)-[r:KNOWS*2..5]->(b)").expect("should parse");
700 let chain = &pattern.chains[0];
701 if let PatternElement::Relationship(rel) = &chain.elements[1] {
702 assert_eq!(rel.variable, Some("r".to_string()));
703 assert_eq!(rel.rel_types, vec!["KNOWS".to_string()]);
704 assert_eq!(rel.min_hops, Some(2));
705 assert_eq!(rel.max_hops, Some(5));
706 } else {
707 panic!("expected relationship");
708 }
709 }
710
711 #[test]
713 fn pattern_var_length_incoming() {
714 let pattern = parse_pattern_str("(a)<-[*1..3]-(b)").expect("should parse");
715 let chain = &pattern.chains[0];
716 if let PatternElement::Relationship(rel) = &chain.elements[1] {
717 assert_eq!(rel.direction, RelDirection::Incoming);
718 assert_eq!(rel.min_hops, Some(1));
719 assert_eq!(rel.max_hops, Some(3));
720 } else {
721 panic!("expected relationship");
722 }
723 }
724
725 #[test]
727 fn pattern_var_length_zero() {
728 let pattern = parse_pattern_str("(a)-[*0..1]->(b)").expect("should parse");
729 let chain = &pattern.chains[0];
730 if let PatternElement::Relationship(rel) = &chain.elements[1] {
731 assert_eq!(rel.min_hops, Some(0));
732 assert_eq!(rel.max_hops, Some(1));
733 } else {
734 panic!("expected relationship");
735 }
736 }
737
738 #[test]
740 fn pattern_var_length_variable_no_type() {
741 let pattern = parse_pattern_str("(a)-[r*2..5]->(b)").expect("should parse");
742 let chain = &pattern.chains[0];
743 if let PatternElement::Relationship(rel) = &chain.elements[1] {
744 assert_eq!(rel.variable, Some("r".to_string()));
745 assert_eq!(rel.rel_types, Vec::<String>::new());
746 assert_eq!(rel.min_hops, Some(2));
747 assert_eq!(rel.max_hops, Some(5));
748 } else {
749 panic!("expected relationship");
750 }
751 }
752
753 #[test]
755 fn pattern_regular_rel_no_hops() {
756 let pattern = parse_pattern_str("(a)-[:KNOWS]->(b)").expect("should parse");
757 let chain = &pattern.chains[0];
758 if let PatternElement::Relationship(rel) = &chain.elements[1] {
759 assert_eq!(rel.min_hops, None);
760 assert_eq!(rel.max_hops, None);
761 } else {
762 panic!("expected relationship");
763 }
764 }
765
766 #[test]
768 fn pattern_rel_variable_only() {
769 let pattern = parse_pattern_str("(a)-[r]->(b)").expect("should parse");
770 let chain = &pattern.chains[0];
771 assert_eq!(
772 chain.elements[1],
773 PatternElement::Relationship(RelationshipPattern {
774 variable: Some("r".to_string()),
775 rel_types: vec![],
776 direction: RelDirection::Outgoing,
777 properties: None,
778 min_hops: None,
779 max_hops: None,
780 })
781 );
782 }
783
784 #[test]
786 fn pattern_empty_rel_brackets() {
787 let pattern = parse_pattern_str("(a)-[]->(b)").expect("should parse");
788 let chain = &pattern.chains[0];
789 assert_eq!(
790 chain.elements[1],
791 PatternElement::Relationship(RelationshipPattern {
792 variable: None,
793 rel_types: vec![],
794 direction: RelDirection::Outgoing,
795 properties: None,
796 min_hops: None,
797 max_hops: None,
798 })
799 );
800 }
801}