1use super::{CompletedMarker, EXPR_RECOVERY, ITEM_RECOVERY, PARAM_RECOVERY, Parser, TYPE_RECOVERY};
28use crate::syntax_kind::SyntaxKind::{self, *};
29
30impl Parser<'_, '_> {
31 const FIELD_RECOVERY: &'static [SyntaxKind] = &[COMMA, R_BRACE, KW_PUBLIC, KW_PRIVATE, KW_CONSTANT];
33 const RETURN_TYPE_RECOVERY: &'static [SyntaxKind] = &[COMMA, R_PAREN, L_BRACE];
35
36 pub fn parse_file_items(&mut self) {
49 loop {
50 self.skip_trivia();
51 if self.at_eof() {
52 break;
53 }
54
55 match self.current() {
56 KW_IMPORT => {
57 self.parse_import();
58 }
59 KW_PROGRAM => {
60 self.parse_program_decl();
61 }
62 KW_CONST | KW_STRUCT | KW_INLINE | AT => {
65 if self.parse_module_item().is_none() {
66 self.error_and_bump("expected module item");
67 }
68 }
69 _ => {
70 self.error_and_bump("expected `import`, `program`, or module item at top level");
71 }
72 }
73 }
74 }
75
76 pub fn parse_module_items(&mut self) {
81 loop {
82 self.skip_trivia();
83 if self.at_eof() {
84 break;
85 }
86
87 if self.parse_module_item().is_none() {
88 self.error_and_bump("expected `const`, `struct`, or `inline` in module");
89 }
90 }
91 }
92
93 fn parse_module_item(&mut self) -> Option<CompletedMarker> {
95 while self.at(AT) {
97 self.parse_annotation();
98 }
99
100 match self.current() {
101 KW_CONST => self.parse_global_const(),
102 KW_STRUCT => self.parse_struct_def(),
103 KW_INLINE => self.parse_function_or_constructor(),
104 _ => None,
105 }
106 }
107
108 fn parse_import(&mut self) -> Option<CompletedMarker> {
110 let m = self.start();
111 self.bump_any(); self.parse_program_id();
115
116 self.expect(SEMICOLON);
117 Some(m.complete(self, IMPORT))
118 }
119
120 fn parse_program_decl(&mut self) -> Option<CompletedMarker> {
122 let m = self.start();
123 self.bump_any(); self.parse_program_id();
127
128 self.expect(L_BRACE);
129
130 while !self.at(R_BRACE) && !self.at_eof() {
132 if self.parse_program_item().is_none() {
133 self.error_recover("expected program item", ITEM_RECOVERY);
135 }
136 }
137
138 self.expect(R_BRACE);
139 Some(m.complete(self, PROGRAM_DECL))
140 }
141
142 fn parse_program_id(&mut self) {
144 self.skip_trivia();
145 if self.at(IDENT) {
146 self.bump_any(); self.expect(DOT);
148 self.expect(KW_ALEO);
149 } else {
150 self.error("expected program name".to_string());
151 }
152 }
153
154 fn parse_program_item(&mut self) -> Option<CompletedMarker> {
156 let has_annotations = self.at(AT);
160 if has_annotations {
161 while self.at(AT) {
163 self.parse_annotation();
164 }
165 }
166
167 match self.current() {
169 KW_STRUCT => self.parse_struct_def(),
170 KW_RECORD => self.parse_record_def(),
171 KW_MAPPING => self.parse_mapping_def(),
172 KW_STORAGE => self.parse_storage_def(),
173 KW_CONST => self.parse_global_const(),
174 KW_FUNCTION | KW_TRANSITION | KW_INLINE | KW_SCRIPT | KW_ASYNC => self.parse_function_or_constructor(),
175 _ => {
176 self.error(format!("expected program item, found {:?}", self.current()));
177 None
178 }
179 }
180 }
181
182 fn parse_annotation(&mut self) {
184 let m = self.start();
185 self.bump_any(); self.skip_trivia();
188 if self.at(IDENT) || self.current().is_keyword() {
191 self.bump_any();
192 } else {
193 self.error("expected annotation name".to_string());
194 }
195
196 if self.eat(L_PAREN) {
200 let mut depth: u32 = 1;
201 while !self.at_eof() && depth > 0 {
202 if self.at(L_PAREN) {
203 depth += 1;
204 } else if self.at(R_PAREN) {
205 depth -= 1;
206 if depth == 0 {
207 break;
208 }
209 }
210 self.bump_any();
211 }
212 self.expect(R_PAREN);
213 }
214
215 m.complete(self, ANNOTATION);
216 }
217
218 fn parse_struct_def(&mut self) -> Option<CompletedMarker> {
220 let m = self.start();
221 self.bump_any(); self.skip_trivia();
225 if self.at(IDENT) {
226 self.bump_any();
227 } else {
228 self.error("expected struct name".to_string());
229 }
230
231 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
233 self.bump_any(); self.parse_const_param_list();
235 }
236
237 self.expect(L_BRACE);
239 self.parse_struct_fields();
240 self.expect(R_BRACE);
241
242 Some(m.complete(self, STRUCT_DEF))
243 }
244
245 fn parse_record_def(&mut self) -> Option<CompletedMarker> {
247 let m = self.start();
248 self.bump_any(); self.skip_trivia();
252 if self.at(IDENT) {
253 self.bump_any();
254 } else {
255 self.error("expected record name".to_string());
256 }
257
258 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
260 self.bump_any(); self.parse_const_param_list();
262 }
263
264 self.expect(L_BRACE);
266 self.parse_struct_fields();
267 self.expect(R_BRACE);
268
269 Some(m.complete(self, RECORD_DEF))
270 }
271
272 fn parse_struct_fields(&mut self) {
274 while !self.at(R_BRACE) && !self.at_eof() {
275 let m = self.start();
277
278 let _ = self.eat(KW_PUBLIC) || self.eat(KW_PRIVATE) || self.eat(KW_CONSTANT);
280
281 self.skip_trivia();
283 if self.at(IDENT) {
284 self.bump_any();
285 } else {
286 m.abandon(self);
287 if !self.at(R_BRACE) {
289 self.error_recover("expected field name", Self::FIELD_RECOVERY);
290 }
291 if self.eat(COMMA) {
293 continue;
294 }
295 break;
296 }
297
298 self.expect(COLON);
300 if self.parse_type().is_none() {
301 self.error_recover("expected type", Self::FIELD_RECOVERY);
302 }
303
304 m.complete(self, STRUCT_MEMBER);
305
306 if !self.eat(COMMA) {
308 break;
309 }
310 }
311 }
312
313 fn parse_mapping_def(&mut self) -> Option<CompletedMarker> {
315 let m = self.start();
316 self.bump_any(); self.skip_trivia();
320 if self.at(IDENT) {
321 self.bump_any();
322 } else {
323 self.error("expected mapping name".to_string());
324 }
325
326 self.expect(COLON);
328 if self.parse_type().is_none() {
329 self.error_recover("expected key type", TYPE_RECOVERY);
330 }
331 self.expect(FAT_ARROW);
332 if self.parse_type().is_none() {
333 self.error_recover("expected value type", TYPE_RECOVERY);
334 }
335
336 self.expect(SEMICOLON);
337 Some(m.complete(self, MAPPING_DEF))
338 }
339
340 fn parse_storage_def(&mut self) -> Option<CompletedMarker> {
342 let m = self.start();
343 self.bump_any(); self.skip_trivia();
347 if self.at(IDENT) {
348 self.bump_any();
349 } else {
350 self.error("expected storage name".to_string());
351 }
352
353 self.expect(COLON);
355 if self.parse_type().is_none() {
356 self.error_recover("expected type", TYPE_RECOVERY);
357 }
358
359 self.expect(SEMICOLON);
360 Some(m.complete(self, STORAGE_DEF))
361 }
362
363 fn parse_global_const(&mut self) -> Option<CompletedMarker> {
365 let m = self.start();
366 self.bump_any(); self.skip_trivia();
370 if self.at(IDENT) {
371 self.bump_any();
372 } else {
373 self.error("expected constant name".to_string());
374 }
375
376 self.expect(COLON);
378 if self.parse_type().is_none() {
379 self.error_recover("expected type", TYPE_RECOVERY);
380 }
381
382 self.expect(EQ);
384 if self.parse_expr().is_none() {
385 self.error_recover("expected expression", EXPR_RECOVERY);
386 }
387
388 self.expect(SEMICOLON);
389 Some(m.complete(self, GLOBAL_CONST))
390 }
391
392 fn parse_function_or_constructor(&mut self) -> Option<CompletedMarker> {
395 let m = self.start();
396
397 self.eat(KW_ASYNC);
399
400 match self.current() {
402 KW_FUNCTION | KW_TRANSITION | KW_INLINE | KW_SCRIPT => {
403 self.parse_function_body();
404 Some(m.complete(self, FUNCTION_DEF))
405 }
406 KW_CONSTRUCTOR => {
407 self.parse_constructor_body();
408 Some(m.complete(self, CONSTRUCTOR_DEF))
409 }
410 _ => {
411 self.error("expected function, transition, inline, or constructor".to_string());
412 m.abandon(self);
413 None
414 }
415 }
416 }
417
418 fn parse_function_body(&mut self) {
420 if !self.eat(KW_FUNCTION) && !self.eat(KW_TRANSITION) && !self.eat(KW_INLINE) && !self.eat(KW_SCRIPT) {
422 self.error("expected function, transition, inline, or script".to_string());
423 }
424
425 self.skip_trivia();
427 if self.at(IDENT) {
428 self.bump_any();
429 } else {
430 self.error("expected function name".to_string());
431 }
432
433 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
435 self.bump_any(); self.parse_const_param_list();
437 }
438
439 self.parse_param_list();
441
442 if self.eat(ARROW) {
444 self.parse_return_type();
445 }
446
447 self.parse_block();
449 }
450
451 fn parse_return_type(&mut self) {
457 self.skip_trivia();
458 if self.at(L_PAREN) {
459 let m = self.start();
461 self.bump_any(); if !self.at(R_PAREN) {
463 let _ = self.eat(KW_PUBLIC) || self.eat(KW_PRIVATE) || self.eat(KW_CONSTANT);
465 if self.parse_type().is_none() {
466 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
467 }
468 while self.eat(COMMA) {
469 if self.at(R_PAREN) {
470 break;
471 }
472 let _ = self.eat(KW_PUBLIC) || self.eat(KW_PRIVATE) || self.eat(KW_CONSTANT);
473 if self.parse_type().is_none() {
474 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
475 }
476 }
477 }
478 self.expect(R_PAREN);
479 m.complete(self, RETURN_TYPE);
480 } else {
481 let _ = self.eat(KW_PUBLIC) || self.eat(KW_PRIVATE) || self.eat(KW_CONSTANT);
483 if self.parse_type().is_none() {
484 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
485 }
486 }
487 }
488
489 fn parse_constructor_body(&mut self) {
491 self.bump_any(); self.parse_param_list();
495
496 self.parse_block();
498 }
499
500 fn parse_param_list(&mut self) {
502 let m = self.start();
503 self.expect(L_PAREN);
504
505 while !self.at(R_PAREN) && !self.at_eof() {
506 self.parse_param();
507 if !self.eat(COMMA) {
508 break;
509 }
510 }
511
512 self.expect(R_PAREN);
513 m.complete(self, PARAM_LIST);
514 }
515
516 fn parse_param(&mut self) {
518 let m = self.start();
519 self.skip_trivia();
520
521 let _ = self.eat(KW_PUBLIC) || self.eat(KW_PRIVATE) || self.eat(KW_CONSTANT);
523
524 self.skip_trivia();
526 if self.at(IDENT) {
527 self.bump_any();
528 } else {
529 self.error("expected parameter name".to_string());
530 }
531
532 self.expect(COLON);
534 if self.parse_type().is_none() {
535 self.error_recover("expected parameter type", PARAM_RECOVERY);
536 }
537
538 m.complete(self, PARAM);
539 }
540}
541
542#[cfg(test)]
543mod tests {
544 use super::*;
545 use crate::{lexer::lex, parser::Parse};
546 use expect_test::{Expect, expect};
547
548 fn check_file(input: &str, expect: Expect) {
549 let (tokens, _) = lex(input);
550 let mut parser = Parser::new(input, &tokens);
551 let root = parser.start();
552 parser.parse_file_items();
553 root.complete(&mut parser, ROOT);
554 let parse: Parse = parser.finish();
555 let output = format!("{:#?}", parse.syntax());
556 expect.assert_eq(&output);
557 }
558
559 fn check_file_no_errors(input: &str) {
560 let (tokens, _) = lex(input);
561 let mut parser = Parser::new(input, &tokens);
562 let root = parser.start();
563 parser.parse_file_items();
564 root.complete(&mut parser, ROOT);
565 let parse: Parse = parser.finish();
566 if !parse.errors().is_empty() {
567 for err in parse.errors() {
568 eprintln!("error at {:?}: {}", err.range, err.message);
569 }
570 eprintln!("tree:\n{:#?}", parse.syntax());
571 panic!("parse had {} error(s)", parse.errors().len());
572 }
573 }
574
575 #[test]
580 fn parse_import() {
581 check_file("import credits.aleo;", expect![[r#"
582 ROOT@0..20
583 IMPORT@0..20
584 KW_IMPORT@0..6 "import"
585 WHITESPACE@6..7 " "
586 IDENT@7..14 "credits"
587 DOT@14..15 "."
588 KW_ALEO@15..19 "aleo"
589 SEMICOLON@19..20 ";"
590 "#]]);
591 }
592
593 #[test]
598 fn parse_program_empty() {
599 check_file("program test.aleo { }", expect![[r#"
600 ROOT@0..21
601 PROGRAM_DECL@0..21
602 KW_PROGRAM@0..7 "program"
603 WHITESPACE@7..8 " "
604 IDENT@8..12 "test"
605 DOT@12..13 "."
606 KW_ALEO@13..17 "aleo"
607 WHITESPACE@17..18 " "
608 L_BRACE@18..19 "{"
609 WHITESPACE@19..20 " "
610 R_BRACE@20..21 "}"
611 "#]]);
612 }
613
614 #[test]
619 fn parse_struct() {
620 check_file("program test.aleo { struct Point { x: u32, y: u32 } }", expect![[r#"
621 ROOT@0..53
622 PROGRAM_DECL@0..53
623 KW_PROGRAM@0..7 "program"
624 WHITESPACE@7..8 " "
625 IDENT@8..12 "test"
626 DOT@12..13 "."
627 KW_ALEO@13..17 "aleo"
628 WHITESPACE@17..18 " "
629 L_BRACE@18..19 "{"
630 STRUCT_DEF@19..51
631 WHITESPACE@19..20 " "
632 KW_STRUCT@20..26 "struct"
633 WHITESPACE@26..27 " "
634 IDENT@27..32 "Point"
635 WHITESPACE@32..33 " "
636 L_BRACE@33..34 "{"
637 STRUCT_MEMBER@34..41
638 WHITESPACE@34..35 " "
639 IDENT@35..36 "x"
640 COLON@36..37 ":"
641 WHITESPACE@37..38 " "
642 TYPE_PATH@38..41
643 KW_U32@38..41 "u32"
644 COMMA@41..42 ","
645 STRUCT_MEMBER@42..49
646 WHITESPACE@42..43 " "
647 IDENT@43..44 "y"
648 COLON@44..45 ":"
649 WHITESPACE@45..46 " "
650 TYPE_PATH@46..49
651 KW_U32@46..49 "u32"
652 WHITESPACE@49..50 " "
653 R_BRACE@50..51 "}"
654 WHITESPACE@51..52 " "
655 R_BRACE@52..53 "}"
656 "#]]);
657 }
658
659 #[test]
664 fn parse_record() {
665 check_file("program test.aleo { record Token { owner: address, amount: u64 } }", expect![[r#"
666 ROOT@0..66
667 PROGRAM_DECL@0..66
668 KW_PROGRAM@0..7 "program"
669 WHITESPACE@7..8 " "
670 IDENT@8..12 "test"
671 DOT@12..13 "."
672 KW_ALEO@13..17 "aleo"
673 WHITESPACE@17..18 " "
674 L_BRACE@18..19 "{"
675 RECORD_DEF@19..64
676 WHITESPACE@19..20 " "
677 KW_RECORD@20..26 "record"
678 WHITESPACE@26..27 " "
679 IDENT@27..32 "Token"
680 WHITESPACE@32..33 " "
681 L_BRACE@33..34 "{"
682 STRUCT_MEMBER@34..49
683 WHITESPACE@34..35 " "
684 IDENT@35..40 "owner"
685 COLON@40..41 ":"
686 WHITESPACE@41..42 " "
687 TYPE_PATH@42..49
688 KW_ADDRESS@42..49 "address"
689 COMMA@49..50 ","
690 STRUCT_MEMBER@50..62
691 WHITESPACE@50..51 " "
692 IDENT@51..57 "amount"
693 COLON@57..58 ":"
694 WHITESPACE@58..59 " "
695 TYPE_PATH@59..62
696 KW_U64@59..62 "u64"
697 WHITESPACE@62..63 " "
698 R_BRACE@63..64 "}"
699 WHITESPACE@64..65 " "
700 R_BRACE@65..66 "}"
701 "#]]);
702 }
703
704 #[test]
709 fn parse_mapping() {
710 check_file("program test.aleo { mapping balances: address => u64; }", expect![[r#"
711 ROOT@0..55
712 PROGRAM_DECL@0..55
713 KW_PROGRAM@0..7 "program"
714 WHITESPACE@7..8 " "
715 IDENT@8..12 "test"
716 DOT@12..13 "."
717 KW_ALEO@13..17 "aleo"
718 WHITESPACE@17..18 " "
719 L_BRACE@18..19 "{"
720 MAPPING_DEF@19..53
721 WHITESPACE@19..20 " "
722 KW_MAPPING@20..27 "mapping"
723 WHITESPACE@27..28 " "
724 IDENT@28..36 "balances"
725 COLON@36..37 ":"
726 WHITESPACE@37..38 " "
727 TYPE_PATH@38..45
728 KW_ADDRESS@38..45 "address"
729 WHITESPACE@45..46 " "
730 FAT_ARROW@46..48 "=>"
731 WHITESPACE@48..49 " "
732 TYPE_PATH@49..52
733 KW_U64@49..52 "u64"
734 SEMICOLON@52..53 ";"
735 WHITESPACE@53..54 " "
736 R_BRACE@54..55 "}"
737 "#]]);
738 }
739
740 #[test]
745 fn parse_function() {
746 check_file("program test.aleo { function add(a: u32, b: u32) -> u32 { return a + b; } }", expect![[r#"
747 ROOT@0..75
748 PROGRAM_DECL@0..75
749 KW_PROGRAM@0..7 "program"
750 WHITESPACE@7..8 " "
751 IDENT@8..12 "test"
752 DOT@12..13 "."
753 KW_ALEO@13..17 "aleo"
754 WHITESPACE@17..18 " "
755 L_BRACE@18..19 "{"
756 FUNCTION_DEF@19..73
757 WHITESPACE@19..20 " "
758 KW_FUNCTION@20..28 "function"
759 WHITESPACE@28..29 " "
760 IDENT@29..32 "add"
761 PARAM_LIST@32..48
762 L_PAREN@32..33 "("
763 PARAM@33..39
764 IDENT@33..34 "a"
765 COLON@34..35 ":"
766 WHITESPACE@35..36 " "
767 TYPE_PATH@36..39
768 KW_U32@36..39 "u32"
769 COMMA@39..40 ","
770 PARAM@40..47
771 WHITESPACE@40..41 " "
772 IDENT@41..42 "b"
773 COLON@42..43 ":"
774 WHITESPACE@43..44 " "
775 TYPE_PATH@44..47
776 KW_U32@44..47 "u32"
777 R_PAREN@47..48 ")"
778 WHITESPACE@48..49 " "
779 ARROW@49..51 "->"
780 WHITESPACE@51..52 " "
781 TYPE_PATH@52..55
782 KW_U32@52..55 "u32"
783 BLOCK@55..73
784 WHITESPACE@55..56 " "
785 L_BRACE@56..57 "{"
786 WHITESPACE@57..58 " "
787 RETURN_STMT@58..71
788 KW_RETURN@58..64 "return"
789 WHITESPACE@64..65 " "
790 BINARY_EXPR@65..70
791 PATH_EXPR@65..67
792 IDENT@65..66 "a"
793 WHITESPACE@66..67 " "
794 PLUS@67..68 "+"
795 WHITESPACE@68..69 " "
796 PATH_EXPR@69..70
797 IDENT@69..70 "b"
798 SEMICOLON@70..71 ";"
799 WHITESPACE@71..72 " "
800 R_BRACE@72..73 "}"
801 WHITESPACE@73..74 " "
802 R_BRACE@74..75 "}"
803 "#]]);
804 }
805
806 #[test]
811 fn parse_function_const_generic_single() {
812 check_file_no_errors("program test.aleo { function foo::[N: u32]() {} }");
813 }
814
815 #[test]
816 fn parse_function_const_generic_multi() {
817 check_file_no_errors("program test.aleo { inline bar::[N: u32, M: u32](arr: u32) -> u32 { return 0u32; } }");
818 }
819
820 #[test]
821 fn parse_function_const_generic_empty() {
822 check_file_no_errors("program test.aleo { inline baz::[]() {} }");
823 }
824
825 #[test]
826 fn parse_async_transition_const_generic() {
827 check_file_no_errors("program test.aleo { async transition t::[N: u32]() -> Future { return async {}; } }");
828 }
829
830 #[test]
831 fn parse_struct_const_generic() {
832 check_file_no_errors("program test.aleo { struct Foo::[N: u32] { arr: u32, } }");
833 }
834
835 #[test]
836 fn parse_struct_const_generic_multi() {
837 check_file_no_errors("program test.aleo { struct Matrix::[M: u32, N: u32] { data: u32, } }");
838 }
839
840 #[test]
841 fn parse_record_const_generic() {
842 check_file_no_errors("program test.aleo { record Bar::[N: u32] { owner: address, } }");
844 }
845
846 #[test]
847 fn parse_transition() {
848 check_file("program test.aleo { transition main(public x: u32) { } }", expect![[r#"
849 ROOT@0..56
850 PROGRAM_DECL@0..56
851 KW_PROGRAM@0..7 "program"
852 WHITESPACE@7..8 " "
853 IDENT@8..12 "test"
854 DOT@12..13 "."
855 KW_ALEO@13..17 "aleo"
856 WHITESPACE@17..18 " "
857 L_BRACE@18..19 "{"
858 FUNCTION_DEF@19..54
859 WHITESPACE@19..20 " "
860 KW_TRANSITION@20..30 "transition"
861 WHITESPACE@30..31 " "
862 IDENT@31..35 "main"
863 PARAM_LIST@35..50
864 L_PAREN@35..36 "("
865 PARAM@36..49
866 KW_PUBLIC@36..42 "public"
867 WHITESPACE@42..43 " "
868 IDENT@43..44 "x"
869 COLON@44..45 ":"
870 WHITESPACE@45..46 " "
871 TYPE_PATH@46..49
872 KW_U32@46..49 "u32"
873 R_PAREN@49..50 ")"
874 WHITESPACE@50..51 " "
875 BLOCK@51..54
876 L_BRACE@51..52 "{"
877 WHITESPACE@52..53 " "
878 R_BRACE@53..54 "}"
879 WHITESPACE@54..55 " "
880 R_BRACE@55..56 "}"
881 "#]]);
882 }
883}