1mod expressions;
24mod grammar;
25mod items;
26mod statements;
27mod types;
28
29use crate::{
30 SyntaxNode,
31 lexer::Token,
32 syntax_kind::{SyntaxKind, SyntaxKind::*},
33};
34pub use grammar::{parse_expression_entry, parse_file, parse_module_entry, parse_statement_entry};
35use rowan::{Checkpoint, GreenNode, GreenNodeBuilder, TextRange, TextSize};
36
37#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct ParseError {
44 pub message: String,
46 pub range: TextRange,
52}
53
54pub struct Parse {
60 green: GreenNode,
62 errors: Vec<ParseError>,
64}
65
66impl Parse {
67 pub fn syntax(&self) -> SyntaxNode {
69 SyntaxNode::new_root(self.green.clone())
70 }
71
72 pub fn errors(&self) -> &[ParseError] {
74 &self.errors
75 }
76
77 pub fn is_ok(&self) -> bool {
79 self.errors.is_empty()
80 }
81
82 pub fn ok(self) -> Result<SyntaxNode, Vec<ParseError>> {
84 if self.errors.is_empty() { Ok(self.syntax()) } else { Err(self.errors) }
85 }
86}
87
88pub struct Marker {
98 checkpoint: Checkpoint,
100 #[cfg(debug_assertions)]
102 completed: bool,
103}
104
105impl Marker {
106 fn new(checkpoint: Checkpoint) -> Self {
107 Self {
108 checkpoint,
109 #[cfg(debug_assertions)]
110 completed: false,
111 }
112 }
113
114 #[allow(unused_mut)]
116 pub fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
117 #[cfg(debug_assertions)]
118 {
119 self.completed = true;
120 }
121 p.builder.start_node_at(self.checkpoint, kind.into());
122 p.builder.finish_node();
123 CompletedMarker { _checkpoint: self.checkpoint, kind }
124 }
125
126 #[allow(unused_mut)] pub fn abandon(mut self, _p: &mut Parser) {
129 #[cfg(debug_assertions)]
130 {
131 self.completed = true;
132 }
133 }
135}
136
137#[cfg(debug_assertions)]
138impl Drop for Marker {
139 fn drop(&mut self) {
140 if !self.completed && !std::thread::panicking() {
141 panic!("Marker was dropped without being completed or abandoned");
142 }
143 }
144}
145
146#[derive(Clone, Copy)]
151pub struct CompletedMarker {
152 _checkpoint: Checkpoint,
154 kind: SyntaxKind,
156}
157
158impl CompletedMarker {
159 pub fn precede(self, _p: &mut Parser) -> Marker {
164 Marker::new(self._checkpoint)
168 }
169
170 #[allow(unused)]
172 pub fn kind(&self) -> SyntaxKind {
173 self.kind
174 }
175}
176
177pub struct Parser<'t, 's> {
187 source: &'s str,
189 tokens: &'t [Token],
191 pos: usize,
193 byte_offset: usize,
195 builder: GreenNodeBuilder<'static>,
197 errors: Vec<ParseError>,
199 paren_depth: u32,
201 brace_depth: u32,
203 bracket_depth: u32,
205}
206
207impl<'t, 's> Parser<'t, 's> {
208 pub fn new(source: &'s str, tokens: &'t [Token]) -> Self {
210 Self {
211 source,
212 tokens,
213 pos: 0,
214 byte_offset: 0,
215 builder: GreenNodeBuilder::new(),
216 errors: Vec::new(),
217 paren_depth: 0,
218 brace_depth: 0,
219 bracket_depth: 0,
220 }
221 }
222
223 pub fn start(&mut self) -> Marker {
232 Marker::new(self.builder.checkpoint())
233 }
234
235 pub fn current(&self) -> SyntaxKind {
241 self.nth(0)
242 }
243
244 pub fn nth(&self, n: usize) -> SyntaxKind {
246 self.nth_non_trivia(n)
247 }
248
249 fn nth_non_trivia(&self, n: usize) -> SyntaxKind {
251 let mut pos = self.pos;
252 let mut count = 0;
253 while pos < self.tokens.len() {
254 let kind = self.tokens[pos].kind;
255 if !kind.is_trivia() {
256 if count == n {
257 return kind;
258 }
259 count += 1;
260 }
261 pos += 1;
262 }
263 EOF
264 }
265
266 pub fn current_including_trivia(&self) -> SyntaxKind {
268 self.tokens.get(self.pos).map(|t| t.kind).unwrap_or(EOF)
269 }
270
271 pub fn at(&self, kind: SyntaxKind) -> bool {
273 self.current() == kind
274 }
275
276 pub fn at_any(&self, kinds: &[SyntaxKind]) -> bool {
278 kinds.contains(&self.current())
279 }
280
281 pub fn at_eof(&self) -> bool {
283 self.at(EOF)
284 }
285
286 #[allow(unused)]
288 pub fn current_text(&self) -> &'s str {
289 if self.pos >= self.tokens.len() {
290 return "";
291 }
292 let len = self.tokens[self.pos].len as usize;
293 &self.source[self.byte_offset..self.byte_offset + len]
294 }
295
296 #[allow(unused)]
298 pub fn nth_text(&self, n: usize) -> &'s str {
299 let mut pos = self.pos;
300 let mut offset = self.byte_offset;
301 let mut count = 0;
302
303 while pos < self.tokens.len() {
304 let token = &self.tokens[pos];
305 if !token.kind.is_trivia() {
306 if count == n {
307 return &self.source[offset..offset + token.len as usize];
308 }
309 count += 1;
310 }
311 offset += token.len as usize;
312 pos += 1;
313 }
314 ""
315 }
316
317 pub fn bump(&mut self) {
323 self.bump_raw();
324 }
325
326 fn bump_raw(&mut self) {
330 if self.pos >= self.tokens.len() {
331 return;
332 }
333 let token = &self.tokens[self.pos];
334
335 match token.kind {
337 L_PAREN => self.paren_depth += 1,
338 R_PAREN => self.paren_depth = self.paren_depth.saturating_sub(1),
339 L_BRACE => self.brace_depth += 1,
340 R_BRACE => self.brace_depth = self.brace_depth.saturating_sub(1),
341 L_BRACKET => self.bracket_depth += 1,
342 R_BRACKET => self.bracket_depth = self.bracket_depth.saturating_sub(1),
343 _ => {}
344 }
345
346 let text = &self.source[self.byte_offset..self.byte_offset + token.len as usize];
347 self.builder.token(token.kind.into(), text);
348 self.byte_offset += token.len as usize;
349 self.pos += 1;
350 }
351
352 pub fn skip_trivia(&mut self) {
354 while self.current_including_trivia().is_trivia() {
355 self.bump_raw();
356 }
357 }
358
359 pub fn eat(&mut self, kind: SyntaxKind) -> bool {
362 self.skip_trivia();
363 if self.current_including_trivia() == kind {
364 self.bump_raw();
365 true
366 } else {
367 false
368 }
369 }
370
371 pub fn bump_any(&mut self) {
373 self.skip_trivia();
374 self.bump_raw();
375 }
376
377 pub fn start_node(&mut self, kind: SyntaxKind) {
386 self.builder.start_node(kind.into());
387 }
388
389 pub fn finish_node(&mut self) {
391 self.builder.finish_node();
392 }
393
394 pub fn checkpoint(&self) -> Checkpoint {
396 self.builder.checkpoint()
397 }
398
399 pub fn start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind) {
401 self.builder.start_node_at(checkpoint, kind.into());
402 }
403
404 pub fn expect(&mut self, kind: SyntaxKind) -> bool {
413 if self.eat(kind) {
414 true
415 } else {
416 self.error(format!("expected {:?}", kind));
417 false
418 }
419 }
420
421 pub fn error(&mut self, message: String) {
423 let pos = TextSize::new(self.byte_offset as u32);
424 self.errors.push(ParseError { message, range: TextRange::empty(pos) });
425 }
426
427 fn error_span(&mut self, message: String, start: usize) {
429 self.errors.push(ParseError {
430 message,
431 range: TextRange::new(TextSize::new(start as u32), TextSize::new(self.byte_offset as u32)),
432 });
433 }
434
435 pub fn error_recover(&mut self, message: &str, recovery: &[SyntaxKind]) {
441 let start = self.byte_offset;
442 self.start_node(ERROR);
443
444 if self.at_any(recovery) && !self.at(R_BRACE) && !self.at_eof() {
448 self.bump_any();
449 }
450
451 while !self.at_eof() && !self.at_any(recovery) {
452 self.bump_any();
453 }
454 self.finish_node();
455
456 self.error_span(message.to_string(), start);
458 }
459
460 pub fn error_and_bump(&mut self, message: &str) {
463 let start = self.byte_offset;
464 self.start_node(ERROR);
465 self.bump_any();
466 self.finish_node();
467 self.error_span(message.to_string(), start);
468 }
469
470 #[allow(unused)]
476 pub fn paren_depth(&self) -> u32 {
477 self.paren_depth
478 }
479
480 #[allow(unused)]
482 pub fn brace_depth(&self) -> u32 {
483 self.brace_depth
484 }
485
486 #[allow(unused)]
488 pub fn bracket_depth(&self) -> u32 {
489 self.bracket_depth
490 }
491
492 #[allow(unused)]
501 pub fn skip_to_balanced(&mut self, open: SyntaxKind, close: SyntaxKind) -> bool {
502 let mut depth: u32 = 1;
503 while !self.at_eof() && depth > 0 {
504 if self.at(open) {
505 depth += 1;
506 } else if self.at(close) {
507 depth -= 1;
508 if depth == 0 {
509 return true;
510 }
511 }
512 self.bump_any();
513 }
514 false
515 }
516
517 pub fn finish(self) -> Parse {
523 Parse { green: self.builder.finish(), errors: self.errors }
524 }
525}
526
527pub const STMT_RECOVERY: &[SyntaxKind] =
533 &[KW_LET, KW_CONST, KW_RETURN, KW_IF, KW_FOR, KW_ASSERT, KW_ASSERT_EQ, KW_ASSERT_NEQ, L_BRACE, R_BRACE, SEMICOLON];
534
535pub const ITEM_RECOVERY: &[SyntaxKind] = &[
537 KW_IMPORT,
538 KW_PROGRAM,
539 KW_FUNCTION,
540 KW_TRANSITION,
541 KW_INLINE,
542 KW_STRUCT,
543 KW_RECORD,
544 KW_MAPPING,
545 KW_STORAGE,
546 KW_CONST,
547 KW_ASYNC,
548 AT,
549 R_BRACE,
550];
551
552pub const EXPR_RECOVERY: &[SyntaxKind] = &[
554 SEMICOLON,
555 COMMA,
556 R_PAREN,
557 R_BRACKET,
558 R_BRACE,
559 KW_LET,
560 KW_CONST,
561 KW_RETURN,
562 KW_IF,
563 KW_FOR,
564 KW_ASSERT,
565 KW_ASSERT_EQ,
566 KW_ASSERT_NEQ,
567];
568
569pub const TYPE_RECOVERY: &[SyntaxKind] = &[COMMA, GT, R_BRACKET, R_PAREN, L_BRACE, R_BRACE, EQ, SEMICOLON, ARROW];
571
572pub const PARAM_RECOVERY: &[SyntaxKind] = &[COMMA, R_PAREN, L_BRACE, ARROW];
574
575#[cfg(test)]
576mod tests {
577 use super::*;
578 use crate::lexer::lex;
579 use expect_test::{Expect, expect};
580
581 fn check_parse(input: &str, parse_fn: impl FnOnce(&mut Parser), expect: Expect) {
583 let (tokens, _) = lex(input);
584 let mut parser = Parser::new(input, &tokens);
585 parse_fn(&mut parser);
586 let parse = parser.finish();
587 let output = format!("{:#?}", parse.syntax());
588 expect.assert_eq(&output);
589 }
590
591 fn check_parse_errors(input: &str, parse_fn: impl FnOnce(&mut Parser), expect: Expect) {
593 let (tokens, _) = lex(input);
594 let mut parser = Parser::new(input, &tokens);
595 parse_fn(&mut parser);
596 let parse = parser.finish();
597 let output = parse
598 .errors()
599 .iter()
600 .map(|e| format!("{}..{}:{}", u32::from(e.range.start()), u32::from(e.range.end()), e.message))
601 .collect::<Vec<_>>()
602 .join("\n");
603 expect.assert_eq(&output);
604 }
605
606 #[test]
611 fn parse_empty() {
612 check_parse(
613 "",
614 |p| {
615 p.start_node(ROOT);
616 p.finish_node();
617 },
618 expect![[r#"
619 ROOT@0..0
620 "#]],
621 );
622 }
623
624 #[test]
625 fn parse_whitespace_only() {
626 check_parse(
627 " ",
628 |p| {
629 p.start_node(ROOT);
630 p.skip_trivia();
631 p.finish_node();
632 },
633 expect![[r#"
634 ROOT@0..3
635 WHITESPACE@0..3 " "
636 "#]],
637 );
638 }
639
640 #[test]
641 fn parse_single_token() {
642 check_parse(
643 "foo",
644 |p| {
645 p.start_node(ROOT);
646 p.skip_trivia();
647 p.bump();
648 p.finish_node();
649 },
650 expect![[r#"
651 ROOT@0..3
652 IDENT@0..3 "foo"
653 "#]],
654 );
655 }
656
657 #[test]
658 fn parse_token_with_trivia() {
659 check_parse(
660 " foo ",
661 |p| {
662 p.start_node(ROOT);
663 p.skip_trivia();
664 p.bump();
665 p.skip_trivia();
666 p.finish_node();
667 },
668 expect![[r#"
669 ROOT@0..7
670 WHITESPACE@0..2 " "
671 IDENT@2..5 "foo"
672 WHITESPACE@5..7 " "
673 "#]],
674 );
675 }
676
677 #[test]
678 fn parse_nested_nodes() {
679 check_parse(
680 "(a)",
681 |p| {
682 p.start_node(ROOT);
683 p.start_node(PAREN_EXPR);
684 p.eat(L_PAREN);
685 p.skip_trivia();
686 p.start_node(NAME_REF);
687 p.bump();
688 p.finish_node();
689 p.eat(R_PAREN);
690 p.finish_node();
691 p.finish_node();
692 },
693 expect![[r#"
694 ROOT@0..3
695 PAREN_EXPR@0..3
696 L_PAREN@0..1 "("
697 NAME_REF@1..2
698 IDENT@1..2 "a"
699 R_PAREN@2..3 ")"
700 "#]],
701 );
702 }
703
704 #[test]
705 fn parse_with_checkpoint() {
706 check_parse(
707 "1 + 2",
708 |p| {
709 p.start_node(ROOT);
710 p.skip_trivia();
711 let checkpoint = p.checkpoint();
712 p.start_node(LITERAL);
713 p.bump();
714 p.finish_node();
715 p.skip_trivia();
716 p.start_node_at(checkpoint, BINARY_EXPR);
717 p.bump();
718 p.skip_trivia();
719 p.start_node(LITERAL);
720 p.bump();
721 p.finish_node();
722 p.finish_node();
723 p.finish_node();
724 },
725 expect![[r#"
726 ROOT@0..5
727 BINARY_EXPR@0..5
728 LITERAL@0..1
729 INTEGER@0..1 "1"
730 WHITESPACE@1..2 " "
731 PLUS@2..3 "+"
732 WHITESPACE@3..4 " "
733 LITERAL@4..5
734 INTEGER@4..5 "2"
735 "#]],
736 );
737 }
738
739 #[test]
740 fn parse_expect_success() {
741 check_parse(
742 ";",
743 |p| {
744 p.start_node(ROOT);
745 p.expect(SEMICOLON);
746 p.finish_node();
747 },
748 expect![[r#"
749 ROOT@0..1
750 SEMICOLON@0..1 ";"
751 "#]],
752 );
753 }
754
755 #[test]
756 fn parse_expect_failure() {
757 check_parse_errors(
758 "foo",
759 |p| {
760 p.start_node(ROOT);
761 p.expect(SEMICOLON);
762 p.finish_node();
763 },
764 expect![[r#"0..0:expected SEMICOLON"#]],
765 );
766 }
767
768 #[test]
769 fn parse_error_recover() {
770 check_parse(
771 "garbage ; ok",
772 |p| {
773 p.start_node(ROOT);
774 p.error_recover("unexpected tokens", &[SEMICOLON]);
775 p.eat(SEMICOLON);
776 p.skip_trivia();
777 p.bump();
778 p.finish_node();
779 },
780 expect![[r#"
781 ROOT@0..12
782 ERROR@0..7
783 IDENT@0..7 "garbage"
784 WHITESPACE@7..8 " "
785 SEMICOLON@8..9 ";"
786 WHITESPACE@9..10 " "
787 IDENT@10..12 "ok"
788 "#]],
789 );
790 }
791
792 #[test]
793 fn parse_error_and_bump() {
794 check_parse(
795 "$",
796 |p| {
797 p.start_node(ROOT);
798 p.skip_trivia();
799 p.error_and_bump("unexpected token");
800 p.finish_node();
801 },
802 expect![[r#"
803 ROOT@0..1
804 ERROR@0..1
805 ERROR@0..1 "$"
806 "#]],
807 );
808 }
809
810 #[test]
811 fn parse_at_and_eat() {
812 check_parse(
813 "let x",
814 |p| {
815 p.start_node(ROOT);
816 assert!(p.at(KW_LET));
817 assert!(!p.at(KW_CONST));
818 p.eat(KW_LET);
819 assert!(p.at(IDENT));
820 p.skip_trivia();
821 p.bump();
822 p.finish_node();
823 },
824 expect![[r#"
825 ROOT@0..5
826 KW_LET@0..3 "let"
827 WHITESPACE@3..4 " "
828 IDENT@4..5 "x"
829 "#]],
830 );
831 }
832
833 #[test]
834 fn parse_nth_lookahead() {
835 check_parse(
836 "a + b * c",
837 |p| {
838 p.start_node(ROOT);
839 assert_eq!(p.nth(0), IDENT);
840 assert_eq!(p.nth(1), PLUS);
841 assert_eq!(p.nth(2), IDENT);
842 assert_eq!(p.nth(3), STAR);
843 assert_eq!(p.nth(4), IDENT);
844 assert_eq!(p.nth(5), EOF);
845 while !p.at_eof() {
846 p.bump_any();
847 }
848 p.finish_node();
849 },
850 expect![[r#"
851 ROOT@0..9
852 IDENT@0..1 "a"
853 WHITESPACE@1..2 " "
854 PLUS@2..3 "+"
855 WHITESPACE@3..4 " "
856 IDENT@4..5 "b"
857 WHITESPACE@5..6 " "
858 STAR@6..7 "*"
859 WHITESPACE@7..8 " "
860 IDENT@8..9 "c"
861 "#]],
862 );
863 }
864
865 #[test]
870 fn marker_complete() {
871 check_parse(
872 "foo",
873 |p| {
874 let m = p.start();
875 p.skip_trivia();
876 p.bump();
877 m.complete(p, ROOT);
878 },
879 expect![[r#"
880 ROOT@0..3
881 IDENT@0..3 "foo"
882 "#]],
883 );
884 }
885
886 #[test]
887 fn marker_precede() {
888 check_parse(
890 "1 + 2",
891 |p| {
892 let root = p.start();
893 p.skip_trivia();
894
895 let lhs_m = p.start();
897 p.bump(); let lhs = lhs_m.complete(p, LITERAL);
899
900 p.skip_trivia();
901
902 let bin_m = lhs.precede(p);
904 p.bump(); p.skip_trivia();
907
908 let rhs_m = p.start();
910 p.bump(); rhs_m.complete(p, LITERAL);
912
913 bin_m.complete(p, BINARY_EXPR);
914 root.complete(p, ROOT);
915 },
916 expect![[r#"
917 ROOT@0..5
918 BINARY_EXPR@0..5
919 LITERAL@0..1
920 INTEGER@0..1 "1"
921 WHITESPACE@1..2 " "
922 PLUS@2..3 "+"
923 WHITESPACE@3..4 " "
924 LITERAL@4..5
925 INTEGER@4..5 "2"
926 "#]],
927 );
928 }
929
930 #[test]
931 fn marker_nested() {
932 check_parse(
933 "(a)",
934 |p| {
935 let root = p.start();
936 let paren = p.start();
937 p.eat(L_PAREN);
938 p.skip_trivia();
939 let name = p.start();
940 p.bump();
941 name.complete(p, NAME_REF);
942 p.eat(R_PAREN);
943 paren.complete(p, PAREN_EXPR);
944 root.complete(p, ROOT);
945 },
946 expect![[r#"
947 ROOT@0..3
948 PAREN_EXPR@0..3
949 L_PAREN@0..1 "("
950 NAME_REF@1..2
951 IDENT@1..2 "a"
952 R_PAREN@2..3 ")"
953 "#]],
954 );
955 }
956
957 fn parse_file(input: &str) -> Parse {
970 let (tokens, _) = lex(input);
971 let mut parser = Parser::new(input, &tokens);
972 let root = parser.start();
973 parser.parse_file_items();
974 root.complete(&mut parser, ROOT);
975 parser.finish()
976 }
977
978 fn parse_stmt_result(input: &str) -> Parse {
980 let (tokens, _) = lex(input);
981 let mut parser = Parser::new(input, &tokens);
982 let root = parser.start();
983 parser.parse_stmt();
984 parser.skip_trivia();
985 root.complete(&mut parser, ROOT);
986 parser.finish()
987 }
988
989 #[test]
990 fn recover_missing_semicolon_let() {
991 let parse = parse_stmt_result("let x = 1");
992 assert!(!parse.errors().is_empty(), "should have errors");
994 let tree = format!("{:#?}", parse.syntax());
996 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
997 }
998
999 #[test]
1000 fn recover_missing_semicolon_return() {
1001 let parse = parse_stmt_result("return 42");
1002 assert!(!parse.errors().is_empty(), "should have errors");
1003 let tree = format!("{:#?}", parse.syntax());
1004 assert!(tree.contains("RETURN_STMT"), "tree should have RETURN_STMT");
1005 }
1006
1007 #[test]
1008 fn recover_missing_expr_in_let() {
1009 let parse = parse_stmt_result("let x = ;");
1010 assert!(!parse.errors().is_empty(), "should have errors");
1011 let tree = format!("{:#?}", parse.syntax());
1012 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1013 }
1014
1015 #[test]
1016 fn recover_missing_type_in_let() {
1017 let parse = parse_stmt_result("let x: = 1;");
1018 assert!(!parse.errors().is_empty(), "should have errors");
1019 let tree = format!("{:#?}", parse.syntax());
1020 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1021 }
1022
1023 #[test]
1024 fn recover_missing_condition_in_if() {
1025 let parse = parse_stmt_result("if { }");
1029 let tree = format!("{:#?}", parse.syntax());
1031 assert!(tree.contains("IF_STMT"), "tree should have IF_STMT");
1032 }
1033
1034 #[test]
1035 fn recover_missing_block_in_if() {
1036 let parse = parse_stmt_result("if x");
1037 assert!(!parse.errors().is_empty(), "should have errors");
1038 let tree = format!("{:#?}", parse.syntax());
1039 assert!(tree.contains("IF_STMT"), "tree should have IF_STMT");
1040 }
1041
1042 #[test]
1043 fn recover_missing_range_in_for() {
1044 let parse = parse_stmt_result("for i in { }");
1045 assert!(!parse.errors().is_empty(), "should have errors");
1046 let tree = format!("{:#?}", parse.syntax());
1047 assert!(tree.contains("FOR_STMT"), "tree should have FOR_STMT");
1048 }
1049
1050 #[test]
1051 fn recover_missing_operand_binary() {
1052 let parse = parse_stmt_result("let x = 1 + ;");
1053 assert!(!parse.errors().is_empty(), "should have errors");
1054 let tree = format!("{:#?}", parse.syntax());
1055 assert!(tree.contains("BINARY_EXPR"), "tree should have BINARY_EXPR");
1056 }
1057
1058 #[test]
1059 fn recover_missing_operand_unary() {
1060 let parse = parse_stmt_result("let x = -;");
1061 assert!(!parse.errors().is_empty(), "should have errors");
1062 let tree = format!("{:#?}", parse.syntax());
1063 assert!(tree.contains("UNARY_EXPR"), "tree should have UNARY_EXPR");
1064 }
1065
1066 #[test]
1067 fn recover_unclosed_paren() {
1068 let parse = parse_stmt_result("let x = (1 + 2;");
1069 assert!(!parse.errors().is_empty(), "should have errors");
1070 let tree = format!("{:#?}", parse.syntax());
1071 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1072 }
1073
1074 #[test]
1075 fn recover_unclosed_bracket() {
1076 let parse = parse_stmt_result("let x = [1, 2;");
1077 assert!(!parse.errors().is_empty(), "should have errors");
1078 let tree = format!("{:#?}", parse.syntax());
1079 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1080 }
1081
1082 #[test]
1083 fn recover_invalid_token_in_expr() {
1084 let parse = parse_stmt_result("let x = 1 @ 2;");
1085 assert!(!parse.errors().is_empty(), "should have errors");
1086 let tree = format!("{:#?}", parse.syntax());
1087 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1088 }
1089
1090 #[test]
1091 fn recover_malformed_assert() {
1092 let parse = parse_stmt_result("assert();");
1093 assert!(!parse.errors().is_empty(), "should have errors");
1094 let tree = format!("{:#?}", parse.syntax());
1095 assert!(tree.contains("ASSERT_STMT"), "tree should have ASSERT_STMT");
1096 }
1097
1098 #[test]
1099 fn recover_malformed_assert_eq() {
1100 let parse = parse_stmt_result("assert_eq(1);");
1101 assert!(!parse.errors().is_empty(), "should have errors");
1102 let tree = format!("{:#?}", parse.syntax());
1103 assert!(tree.contains("ASSERT_EQ_STMT"), "tree should have ASSERT_EQ_STMT");
1104 }
1105
1106 #[test]
1107 fn recover_missing_assignment_rhs() {
1108 let parse = parse_stmt_result("x = ;");
1109 assert!(!parse.errors().is_empty(), "should have errors");
1110 let tree = format!("{:#?}", parse.syntax());
1111 assert!(tree.contains("ASSIGN_STMT"), "tree should have ASSIGN_STMT");
1112 }
1113
1114 #[test]
1115 fn recover_malformed_function_missing_params() {
1116 let parse = parse_file("program test.aleo { function foo { } }");
1117 assert!(!parse.errors().is_empty(), "should have errors");
1118 let tree = format!("{:#?}", parse.syntax());
1119 assert!(tree.contains("PROGRAM_DECL"), "tree should have PROGRAM_DECL");
1120 assert!(tree.contains("FUNCTION_DEF"), "tree should have FUNCTION_DEF");
1121 }
1122
1123 #[test]
1124 fn recover_malformed_function_missing_body() {
1125 let parse = parse_file("program test.aleo { function foo() }");
1126 assert!(!parse.errors().is_empty(), "should have errors");
1127 let tree = format!("{:#?}", parse.syntax());
1128 assert!(tree.contains("PROGRAM_DECL"), "tree should have PROGRAM_DECL");
1129 assert!(tree.contains("FUNCTION_DEF"), "tree should have FUNCTION_DEF");
1130 }
1131
1132 #[test]
1133 fn recover_malformed_struct_field() {
1134 let parse = parse_file("program test.aleo { struct Foo { x, y: u32 } }");
1135 assert!(!parse.errors().is_empty(), "should have errors");
1136 let tree = format!("{:#?}", parse.syntax());
1137 assert!(tree.contains("STRUCT_DEF"), "tree should have STRUCT_DEF");
1138 }
1139
1140 #[test]
1141 fn recover_malformed_mapping() {
1142 let parse = parse_file("program test.aleo { mapping balances: => u64; }");
1143 assert!(!parse.errors().is_empty(), "should have errors");
1144 let tree = format!("{:#?}", parse.syntax());
1145 assert!(tree.contains("MAPPING_DEF"), "tree should have MAPPING_DEF");
1146 }
1147
1148 #[test]
1149 fn recover_multiple_errors_in_function() {
1150 let parse = parse_file(
1151 r#"program test.aleo {
1152 function foo() {
1153 let x = ;
1154 let y: = 1;
1155 return x +;
1156 }
1157 }"#,
1158 );
1159 assert!(parse.errors().len() >= 3, "should have at least 3 errors");
1161 let tree = format!("{:#?}", parse.syntax());
1162 assert!(tree.contains("FUNCTION_DEF"), "tree should have FUNCTION_DEF");
1163 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1164 assert!(tree.contains("RETURN_STMT"), "tree should have RETURN_STMT");
1165 }
1166
1167 #[test]
1168 fn recover_valid_items_after_error() {
1169 let parse = parse_file(
1170 r#"program test.aleo {
1171 struct Invalid { x }
1172 struct Valid { y: u32 }
1173 }"#,
1174 );
1175 assert!(!parse.errors().is_empty(), "should have errors");
1177 let tree = format!("{:#?}", parse.syntax());
1178 let struct_count = tree.matches("STRUCT_DEF").count();
1180 assert_eq!(struct_count, 2, "should have 2 struct definitions");
1181 }
1182
1183 #[test]
1184 fn recover_empty_tuple_pattern() {
1185 let parse = parse_stmt_result("let () = foo;");
1186 let tree = format!("{:#?}", parse.syntax());
1188 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1189 assert!(tree.contains("TUPLE_PATTERN"), "tree should have TUPLE_PATTERN");
1190 }
1191
1192 #[test]
1193 fn recover_nested_errors() {
1194 let parse = parse_stmt_result("let x = ((1 + ) + 2);");
1196 assert!(!parse.errors().is_empty(), "should have errors");
1197 let tree = format!("{:#?}", parse.syntax());
1198 assert!(tree.contains("LET_STMT"), "tree should have LET_STMT");
1199 assert!(tree.contains("PAREN_EXPR"), "tree should have PAREN_EXPR");
1200 }
1201
1202 #[test]
1203 fn recover_ternary_missing_then() {
1204 let parse = parse_stmt_result("let x = cond ? : 2;");
1205 assert!(!parse.errors().is_empty(), "should have errors");
1206 let tree = format!("{:#?}", parse.syntax());
1207 assert!(tree.contains("TERNARY_EXPR"), "tree should have TERNARY_EXPR");
1208 }
1209
1210 #[test]
1211 fn recover_ternary_missing_else() {
1212 let parse = parse_stmt_result("let x = cond ? 1 :;");
1213 assert!(!parse.errors().is_empty(), "should have errors");
1214 let tree = format!("{:#?}", parse.syntax());
1215 assert!(tree.contains("TERNARY_EXPR"), "tree should have TERNARY_EXPR");
1216 }
1217
1218 #[test]
1219 fn never_panics_on_garbage() {
1220 let garbage_inputs = [
1222 "@#$%^&*()",
1223 "{{{{{{",
1224 "}}}}}}",
1225 "let let let",
1226 "program { program { program",
1227 "struct struct struct",
1228 ";;;;;;",
1229 "++ -- ** //",
1230 "",
1231 " \n\t\r ",
1232 "🦀🦀🦀", ];
1234
1235 for input in garbage_inputs {
1236 let _ = parse_file(input);
1238 }
1239 }
1240}