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 MODULE_ITEM_RECOVERY: &'static [SyntaxKind] = &[KW_CONST, KW_STRUCT, KW_FN, KW_FINAL, AT];
35 const PROGRAM_ITEM_EXPECTED: &'static [SyntaxKind] = &[
37 R_BRACE,
38 AT,
39 KW_RECORD,
40 KW_STRUCT,
41 KW_FN,
42 KW_FINAL,
43 KW_CONST,
44 KW_MAPPING,
45 KW_STORAGE,
46 KW_SCRIPT,
47 KW_INTERFACE,
48 ];
49 const RETURN_TYPE_RECOVERY: &'static [SyntaxKind] = &[COMMA, R_PAREN, L_BRACE];
51 const STRUCT_NAME_RECOVERY: &'static [SyntaxKind] = &[
53 L_BRACE,
54 R_BRACE,
55 SEMICOLON,
56 KW_IMPORT,
57 KW_PROGRAM,
58 KW_CONST,
59 KW_STRUCT,
60 KW_RECORD,
61 KW_FN,
62 KW_FINAL,
63 KW_MAPPING,
64 KW_STORAGE,
65 KW_SCRIPT,
66 KW_INTERFACE,
67 AT,
68 ];
69
70 fn eat_visibility(&mut self) -> Option<SyntaxKind> {
73 if self.eat(KW_PUBLIC) {
74 Some(KW_PUBLIC)
75 } else if self.eat(KW_PRIVATE) {
76 Some(KW_PRIVATE)
77 } else if self.eat(KW_CONSTANT) {
78 Some(KW_CONSTANT)
79 } else {
80 None
81 }
82 }
83
84 pub fn parse_file_items(&mut self) {
97 loop {
98 self.skip_trivia();
99 if self.at_eof() {
100 break;
101 }
102
103 self.erroring = false;
105
106 match self.current() {
107 KW_IMPORT => {
108 self.parse_import();
109 }
110 KW_PROGRAM => {
111 self.parse_program_decl();
112 }
113 KW_CONST | KW_STRUCT | KW_FN | KW_FINAL | AT => {
116 if self.parse_module_item().is_none() {
117 self.error_and_bump("expected module item");
118 }
119 }
120 KW_INTERFACE => {
121 self.parse_interface_def();
122 }
123 _ => {
124 self.error("expected `import`, `program`, or module item at top level");
125 self.recover(&[KW_IMPORT, KW_PROGRAM, KW_CONST, KW_STRUCT, KW_FN, KW_FINAL, KW_INTERFACE, AT]);
126 }
127 }
128 }
129 }
130
131 pub fn parse_module_items(&mut self) {
136 loop {
137 self.skip_trivia();
138 if self.at_eof() {
139 break;
140 }
141
142 self.erroring = false;
144
145 if self.parse_module_item().is_none() {
146 self.error("expected `const`, `struct`, or `fn` in module");
147 self.recover(Self::MODULE_ITEM_RECOVERY);
148 }
149 }
150 }
151
152 fn parse_module_item(&mut self) -> Option<CompletedMarker> {
156 match self.current() {
157 KW_CONST => self.parse_global_const(),
158 KW_STRUCT => self.parse_composite_def(STRUCT_DEF),
159 KW_INTERFACE => self.parse_interface_def(),
160 AT | KW_FN | KW_FINAL => self.parse_function_or_constructor(),
161 _ => None,
162 }
163 }
164
165 fn parse_import(&mut self) -> Option<CompletedMarker> {
167 let m = self.start();
168 self.bump_any(); self.parse_program_id();
172
173 self.expect(SEMICOLON);
174 Some(m.complete(self, IMPORT))
175 }
176
177 fn parse_program_decl(&mut self) -> Option<CompletedMarker> {
179 let m = self.start();
180 self.bump_any(); self.parse_program_id();
184
185 self.skip_trivia();
186 if self.eat(COLON) {
188 self.skip_trivia();
189 self.erroring = false;
191 self.parse_parent_list();
192 }
193
194 self.expect(L_BRACE);
195
196 while !self.at(R_BRACE) && !self.at_eof() {
198 self.erroring = false;
200 if self.parse_program_item().is_none() {
201 self.recover(ITEM_RECOVERY);
203 }
204 }
205
206 self.expect(R_BRACE);
207 Some(m.complete(self, PROGRAM_DECL))
208 }
209
210 fn parse_program_id(&mut self) {
212 self.skip_trivia();
213 if self.at(IDENT) {
214 self.bump_any(); self.expect(DOT);
216 if !self.eat(KW_ALEO) {
217 if self.at(IDENT) {
218 self.bump_any();
221 } else {
222 self.error("expected 'aleo'");
223 }
224 }
225 } else {
226 self.error("expected program name");
227 }
228 }
229
230 fn parse_program_item(&mut self) -> Option<CompletedMarker> {
235 match self.current() {
239 AT => self.parse_function_or_constructor(),
240 KW_STRUCT => self.parse_composite_def(STRUCT_DEF),
241 KW_RECORD => self.parse_composite_def(RECORD_DEF),
242 KW_MAPPING => self.parse_mapping_def(),
243 KW_STORAGE => self.parse_storage_def(),
244 KW_CONST => self.parse_global_const(),
245 KW_FN | KW_FINAL | KW_CONSTRUCTOR => self.parse_function_or_constructor(),
246 KW_SCRIPT => {
247 self.error("'script' functions are no longer supported; use @test on entry point functions instead");
248 self.bump_any();
249 None
250 }
251 KW_INTERFACE => self.parse_interface_def(),
252 _ => {
253 let expected: Vec<&str> = Self::PROGRAM_ITEM_EXPECTED.iter().map(|k| k.user_friendly_name()).collect();
254 self.error_unexpected(self.current(), &expected);
255 None
256 }
257 }
258 }
259
260 fn parse_annotation(&mut self) {
262 let m = self.start();
263 self.bump_any(); if self.current_including_trivia().is_trivia() {
267 self.error_unexpected(self.current(), &["an identifier", "'program'"]);
268 self.skip_trivia();
269 if self.at(IDENT) || self.current().is_keyword() {
271 self.bump_any();
272 }
273 } else if self.at(IDENT) || self.current().is_keyword() {
274 self.bump_any();
277 } else {
278 self.error("expected annotation name");
279 }
280
281 if self.eat(L_PAREN) {
284 if !self.at(R_PAREN) {
285 self.parse_annotation_member();
286 while self.eat(COMMA) {
287 if self.at(R_PAREN) {
288 break;
289 }
290 self.erroring = false;
292 self.parse_annotation_member();
293 }
294 }
295 if !self.at(R_PAREN) && !self.at_eof() {
297 self.error_unexpected(self.current(), &["')'", "','"]);
298 while !self.at(R_PAREN) && !self.at_eof() {
300 self.bump_any();
301 }
302 }
303 self.expect(R_PAREN);
304 }
305
306 m.complete(self, ANNOTATION);
307 }
308
309 fn parse_annotation_member(&mut self) {
311 let m = self.start();
312 if self.at(IDENT) || self.at(KW_ADDRESS) || self.at(KW_MAPPING) {
314 self.bump_any();
315 } else {
316 self.error_unexpected(self.current(), &["an identifier", "')'", "'address", "'mapping'"]);
317 while !self.at(COMMA) && !self.at(R_PAREN) && !self.at_eof() {
319 self.bump_any();
320 }
321 m.abandon(self);
322 return;
323 }
324 self.expect(EQ);
325 if self.at(STRING) {
326 self.bump_any();
327 } else {
328 self.error("expected string literal for annotation value");
329 }
330 m.complete(self, ANNOTATION_PAIR);
331 }
332
333 fn parse_composite_def(&mut self, kind: SyntaxKind) -> Option<CompletedMarker> {
335 let m = self.start();
336 let label = if kind == STRUCT_DEF { "struct" } else { "record" };
337 self.bump_any(); self.skip_trivia();
341 if self.at(IDENT) {
342 self.bump_any();
343 } else {
344 self.error(format!("expected {label} name"));
345 self.recover(Self::STRUCT_NAME_RECOVERY);
346 return Some(m.complete(self, ERROR));
347 }
348
349 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
351 self.bump_any(); self.parse_const_param_list();
353 }
354
355 self.expect(L_BRACE);
357 self.parse_struct_fields_until(&[R_BRACE]);
358 self.expect(R_BRACE);
359
360 Some(m.complete(self, kind))
361 }
362
363 fn parse_struct_fields_until(&mut self, closing_symbols: &[SyntaxKind]) {
365 while !closing_symbols.iter().any(|closing| self.at(*closing)) && !self.at_eof() {
366 self.skip_trivia();
368 let m = self.start();
369
370 let vis = self.eat_visibility();
372
373 self.skip_trivia();
375 if self.at(IDENT) {
376 self.bump_any();
377 } else {
378 m.abandon(self);
379 if !closing_symbols.iter().any(|closing| self.at(*closing)) {
381 self.error_recover("expected field name", Self::FIELD_RECOVERY);
382 }
383 if self.eat(COMMA) {
385 continue;
386 }
387 break;
388 }
389
390 self.expect(COLON);
392 if self.parse_type().is_none() {
393 self.error_recover("expected type", Self::FIELD_RECOVERY);
394 }
395
396 let kind = match vis {
397 Some(KW_PUBLIC) => STRUCT_MEMBER_PUBLIC,
398 Some(KW_PRIVATE) => STRUCT_MEMBER_PRIVATE,
399 Some(KW_CONSTANT) => STRUCT_MEMBER_CONSTANT,
400 _ => STRUCT_MEMBER,
401 };
402 m.complete(self, kind);
403
404 if !self.eat(COMMA) {
406 if !closing_symbols.iter().any(|closing| self.at(*closing)) && !self.at_eof() {
410 self.error("expected ','");
411 self.erroring = false;
413 }
414 }
415 }
416 }
417
418 fn parse_mapping_def(&mut self) -> Option<CompletedMarker> {
420 let m = self.start();
421 self.bump_any(); self.skip_trivia();
425 if self.at(IDENT) {
426 self.bump_any();
427 } else {
428 self.error("expected mapping name");
429 }
430
431 self.expect(COLON);
433 if self.parse_type().is_none() {
434 self.error_recover("expected key type", TYPE_RECOVERY);
435 }
436 self.expect(FAT_ARROW);
437 if self.parse_type().is_none() {
438 self.error_recover("expected value type", TYPE_RECOVERY);
439 }
440
441 self.expect(SEMICOLON);
442 Some(m.complete(self, MAPPING_DEF))
443 }
444
445 fn parse_storage_def(&mut self) -> Option<CompletedMarker> {
447 let m = self.start();
448 self.bump_any(); self.skip_trivia();
452 if self.at(IDENT) {
453 self.bump_any();
454 } else {
455 self.error("expected storage name");
456 }
457
458 self.expect(COLON);
460 if self.parse_type().is_none() {
461 self.error_recover("expected type", TYPE_RECOVERY);
462 }
463
464 self.expect(SEMICOLON);
465 Some(m.complete(self, STORAGE_DEF))
466 }
467
468 fn parse_global_const(&mut self) -> Option<CompletedMarker> {
470 let m = self.start();
471 self.bump_any(); self.skip_trivia();
475 if self.at(IDENT) {
476 self.bump_any();
477 } else {
478 self.error("expected constant name");
479 self.recover(&[SEMICOLON]);
480 self.eat(SEMICOLON);
481 return Some(m.complete(self, GLOBAL_CONST));
482 }
483
484 self.expect(COLON);
486 if self.parse_type().is_none() {
487 self.error_recover("expected type", TYPE_RECOVERY);
488 }
489
490 self.expect(EQ);
492 if self.parse_expr().is_none() {
493 self.error_recover("expected expression", EXPR_RECOVERY);
494 }
495
496 self.expect(SEMICOLON);
497 Some(m.complete(self, GLOBAL_CONST))
498 }
499
500 fn parse_function_or_constructor(&mut self) -> Option<CompletedMarker> {
504 let m = self.start();
505
506 while self.at(AT) {
508 self.parse_annotation();
509 }
510
511 let ate_final = self.eat(KW_FINAL);
513
514 match self.current() {
516 KW_FN => {
517 self.parse_function_body();
518 let kind = if ate_final { FINAL_FN_DEF } else { FUNCTION_DEF };
519 Some(m.complete(self, kind))
520 }
521 KW_CONSTRUCTOR => {
522 self.parse_constructor_body();
523 Some(m.complete(self, CONSTRUCTOR_DEF))
524 }
525 _ => {
526 self.error("expected 'fn' or 'constructor'");
527 m.abandon(self);
528 None
529 }
530 }
531 }
532
533 fn parse_function_body(&mut self) {
535 if !self.eat(KW_FN) {
537 self.error("expected 'fn'");
538 }
539
540 self.skip_trivia();
542 if self.at(IDENT) {
543 self.bump_any();
544 } else {
545 self.error("expected function name");
546 }
547
548 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
550 self.bump_any(); self.parse_const_param_list();
552 }
553
554 self.parse_param_list();
556
557 if self.eat(ARROW) {
559 self.parse_return_type();
560 }
561
562 self.parse_block();
564 }
565
566 fn parse_return_type(&mut self) {
572 self.skip_trivia();
573 if self.at(L_PAREN) {
574 let m = self.start();
576 self.bump_any(); if !self.at(R_PAREN) {
578 self.eat_visibility();
580 if self.parse_type().is_none() {
581 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
582 }
583 while self.eat(COMMA) {
584 if self.at(R_PAREN) {
585 break;
586 }
587 self.eat_visibility();
588 if self.parse_type().is_none() {
589 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
590 }
591 }
592 }
593 self.expect(R_PAREN);
594 m.complete(self, RETURN_TYPE);
595 } else {
596 self.eat_visibility();
598 if self.parse_type().is_none() {
599 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
600 }
601 }
602 }
603
604 fn parse_constructor_body(&mut self) {
606 self.bump_any(); self.parse_param_list();
610
611 self.parse_block();
613 }
614
615 fn parse_param_list(&mut self) {
617 let m = self.start();
618 self.expect(L_PAREN);
619
620 while !self.at(R_PAREN) && !self.at_eof() {
621 self.erroring = false;
623 self.parse_param();
624 if !self.eat(COMMA) {
625 break;
626 }
627 }
628
629 self.expect(R_PAREN);
630 m.complete(self, PARAM_LIST);
631 }
632
633 fn parse_parent_list(&mut self) {
635 let m = self.start();
636 self.parse_type();
637 self.skip_trivia();
638
639 while self.at(PLUS) && !self.at_eof() {
640 self.bump_any(); self.skip_trivia();
642 self.parse_type();
643 self.skip_trivia();
644 }
645
646 m.complete(self, PARENT_LIST);
647 }
648
649 fn parse_param(&mut self) {
651 let m = self.start();
652 self.skip_trivia();
653
654 let vis = self.eat_visibility();
656
657 self.skip_trivia();
659 if self.at(IDENT) {
660 self.bump_any();
661 } else {
662 self.error("expected parameter name");
663 }
664
665 self.expect(COLON);
667 if self.parse_type().is_none() {
668 self.error_recover("expected parameter type", PARAM_RECOVERY);
669 }
670
671 let kind = match vis {
672 Some(KW_PUBLIC) => PARAM_PUBLIC,
673 Some(KW_PRIVATE) => PARAM_PRIVATE,
674 Some(KW_CONSTANT) => PARAM_CONSTANT,
675 _ => PARAM,
676 };
677 m.complete(self, kind);
678 }
679
680 fn parse_interface_def(&mut self) -> Option<CompletedMarker> {
686 let m = self.start();
687 self.bump_any(); self.skip_trivia();
691 if self.at(IDENT) {
692 self.bump_any();
693 } else {
694 self.error("expected parameter name");
695 }
696
697 self.skip_trivia();
699 if self.eat(COLON) {
700 self.skip_trivia();
701 self.parse_parent_list();
702 }
703
704 self.expect(L_BRACE);
706 while !self.at(R_BRACE) && !self.at_eof() {
707 self.erroring = false;
708 if !self.parse_interface_item() {
709 self.error_and_bump("expected function or record prototype");
710 }
711 }
712 self.expect(R_BRACE);
713
714 Some(m.complete(self, INTERFACE_DEF))
715 }
716
717 fn parse_interface_item(&mut self) -> bool {
719 match self.current() {
720 KW_FN => {
721 self.parse_fn_prototype();
722 true
723 }
724 KW_RECORD => {
725 self.parse_record_prototype();
726 true
727 }
728 KW_MAPPING => {
729 self.parse_mapping_def();
730 true
731 }
732 KW_STORAGE => {
733 self.parse_storage_def();
734 true
735 }
736 _ => false,
737 }
738 }
739
740 fn parse_fn_prototype(&mut self) -> Option<CompletedMarker> {
742 let m = self.start();
743 self.bump_any(); self.skip_trivia();
747 if self.at(IDENT) {
748 self.bump_any();
749 } else {
750 self.error("expected function name");
751 }
752
753 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
755 self.bump_any(); self.parse_const_param_list();
757 }
758
759 self.parse_param_list();
761
762 if self.eat(ARROW) {
764 self.parse_return_type();
765 }
766
767 self.expect(SEMICOLON);
768 Some(m.complete(self, FN_PROTOTYPE_DEF))
769 }
770
771 fn parse_record_prototype(&mut self) -> Option<CompletedMarker> {
773 let m = self.start();
774 self.bump_any(); self.skip_trivia();
777 if self.at(IDENT) {
778 self.bump_any();
779 } else {
780 self.error("expected record name");
781 }
782
783 if self.at(SEMICOLON) {
784 self.bump_any();
786 } else {
787 self.expect(L_BRACE);
789 self.parse_struct_fields_until(&[DOT_DOT, R_BRACE]);
790 if self.eat(DOT_DOT) {
791 self.expect(R_BRACE);
792 } else {
793 self.error("expected `..`; fully constraining record fields in interfaces is not yet supported");
794 self.expect(R_BRACE);
795 }
796 }
797
798 Some(m.complete(self, RECORD_PROTOTYPE_DEF))
799 }
800}
801
802#[cfg(test)]
803mod tests {
804 use super::*;
805 use crate::{lexer::lex, parser::Parse};
806 use expect_test::{Expect, expect};
807
808 fn check_file(input: &str, expect: Expect) {
809 let (tokens, _) = lex(input);
810 let mut parser = Parser::new(input, &tokens);
811 let root = parser.start();
812 parser.parse_file_items();
813 root.complete(&mut parser, ROOT);
814 let parse: Parse = parser.finish(vec![]);
815 let output = format!("{:#?}", parse.syntax());
816 expect.assert_eq(&output);
817 }
818
819 fn check_file_no_errors(input: &str) {
820 let (tokens, _) = lex(input);
821 let mut parser = Parser::new(input, &tokens);
822 let root = parser.start();
823 parser.parse_file_items();
824 root.complete(&mut parser, ROOT);
825 let parse: Parse = parser.finish(vec![]);
826 if !parse.errors().is_empty() {
827 for err in parse.errors() {
828 eprintln!("error at {:?}: {}", err.range, err.message);
829 }
830 eprintln!("tree:\n{:#?}", parse.syntax());
831 panic!("parse had {} error(s)", parse.errors().len());
832 }
833 }
834
835 #[test]
840 fn parse_import() {
841 check_file("import credits.aleo;", expect![[r#"
842 ROOT@0..20
843 IMPORT@0..20
844 KW_IMPORT@0..6 "import"
845 WHITESPACE@6..7 " "
846 IDENT@7..14 "credits"
847 DOT@14..15 "."
848 KW_ALEO@15..19 "aleo"
849 SEMICOLON@19..20 ";"
850 "#]]);
851 }
852
853 #[test]
858 fn parse_program_empty() {
859 check_file("program test.aleo { }", expect![[r#"
860 ROOT@0..21
861 PROGRAM_DECL@0..21
862 KW_PROGRAM@0..7 "program"
863 WHITESPACE@7..8 " "
864 IDENT@8..12 "test"
865 DOT@12..13 "."
866 KW_ALEO@13..17 "aleo"
867 WHITESPACE@17..18 " "
868 L_BRACE@18..19 "{"
869 WHITESPACE@19..20 " "
870 R_BRACE@20..21 "}"
871 "#]]);
872 }
873
874 #[test]
879 fn parse_struct() {
880 check_file("program test.aleo { struct Point { x: u32, y: u32 } }", expect![[r#"
881 ROOT@0..53
882 PROGRAM_DECL@0..53
883 KW_PROGRAM@0..7 "program"
884 WHITESPACE@7..8 " "
885 IDENT@8..12 "test"
886 DOT@12..13 "."
887 KW_ALEO@13..17 "aleo"
888 WHITESPACE@17..18 " "
889 L_BRACE@18..19 "{"
890 STRUCT_DEF@19..51
891 WHITESPACE@19..20 " "
892 KW_STRUCT@20..26 "struct"
893 WHITESPACE@26..27 " "
894 IDENT@27..32 "Point"
895 WHITESPACE@32..33 " "
896 L_BRACE@33..34 "{"
897 WHITESPACE@34..35 " "
898 STRUCT_MEMBER@35..41
899 IDENT@35..36 "x"
900 COLON@36..37 ":"
901 WHITESPACE@37..38 " "
902 TYPE_PRIMITIVE@38..41
903 KW_U32@38..41 "u32"
904 COMMA@41..42 ","
905 WHITESPACE@42..43 " "
906 STRUCT_MEMBER@43..49
907 IDENT@43..44 "y"
908 COLON@44..45 ":"
909 WHITESPACE@45..46 " "
910 TYPE_PRIMITIVE@46..49
911 KW_U32@46..49 "u32"
912 WHITESPACE@49..50 " "
913 R_BRACE@50..51 "}"
914 WHITESPACE@51..52 " "
915 R_BRACE@52..53 "}"
916 "#]]);
917 }
918
919 #[test]
924 fn parse_record() {
925 check_file("program test.aleo { record Token { owner: address, amount: u64 } }", expect![[r#"
926 ROOT@0..66
927 PROGRAM_DECL@0..66
928 KW_PROGRAM@0..7 "program"
929 WHITESPACE@7..8 " "
930 IDENT@8..12 "test"
931 DOT@12..13 "."
932 KW_ALEO@13..17 "aleo"
933 WHITESPACE@17..18 " "
934 L_BRACE@18..19 "{"
935 RECORD_DEF@19..64
936 WHITESPACE@19..20 " "
937 KW_RECORD@20..26 "record"
938 WHITESPACE@26..27 " "
939 IDENT@27..32 "Token"
940 WHITESPACE@32..33 " "
941 L_BRACE@33..34 "{"
942 WHITESPACE@34..35 " "
943 STRUCT_MEMBER@35..49
944 IDENT@35..40 "owner"
945 COLON@40..41 ":"
946 WHITESPACE@41..42 " "
947 TYPE_PRIMITIVE@42..49
948 KW_ADDRESS@42..49 "address"
949 COMMA@49..50 ","
950 WHITESPACE@50..51 " "
951 STRUCT_MEMBER@51..62
952 IDENT@51..57 "amount"
953 COLON@57..58 ":"
954 WHITESPACE@58..59 " "
955 TYPE_PRIMITIVE@59..62
956 KW_U64@59..62 "u64"
957 WHITESPACE@62..63 " "
958 R_BRACE@63..64 "}"
959 WHITESPACE@64..65 " "
960 R_BRACE@65..66 "}"
961 "#]]);
962 }
963
964 #[test]
969 fn parse_mapping() {
970 check_file("program test.aleo { mapping balances: address => u64; }", expect![[r#"
971 ROOT@0..55
972 PROGRAM_DECL@0..55
973 KW_PROGRAM@0..7 "program"
974 WHITESPACE@7..8 " "
975 IDENT@8..12 "test"
976 DOT@12..13 "."
977 KW_ALEO@13..17 "aleo"
978 WHITESPACE@17..18 " "
979 L_BRACE@18..19 "{"
980 MAPPING_DEF@19..53
981 WHITESPACE@19..20 " "
982 KW_MAPPING@20..27 "mapping"
983 WHITESPACE@27..28 " "
984 IDENT@28..36 "balances"
985 COLON@36..37 ":"
986 WHITESPACE@37..38 " "
987 TYPE_PRIMITIVE@38..45
988 KW_ADDRESS@38..45 "address"
989 WHITESPACE@45..46 " "
990 FAT_ARROW@46..48 "=>"
991 WHITESPACE@48..49 " "
992 TYPE_PRIMITIVE@49..52
993 KW_U64@49..52 "u64"
994 SEMICOLON@52..53 ";"
995 WHITESPACE@53..54 " "
996 R_BRACE@54..55 "}"
997 "#]]);
998 }
999
1000 #[test]
1005 fn parse_function() {
1006 check_file("program test.aleo { fn add(a: u32, b: u32) -> u32 { return a + b; } }", expect![[r#"
1007 ROOT@0..69
1008 PROGRAM_DECL@0..69
1009 KW_PROGRAM@0..7 "program"
1010 WHITESPACE@7..8 " "
1011 IDENT@8..12 "test"
1012 DOT@12..13 "."
1013 KW_ALEO@13..17 "aleo"
1014 WHITESPACE@17..18 " "
1015 L_BRACE@18..19 "{"
1016 FUNCTION_DEF@19..67
1017 WHITESPACE@19..20 " "
1018 KW_FN@20..22 "fn"
1019 WHITESPACE@22..23 " "
1020 IDENT@23..26 "add"
1021 PARAM_LIST@26..42
1022 L_PAREN@26..27 "("
1023 PARAM@27..33
1024 IDENT@27..28 "a"
1025 COLON@28..29 ":"
1026 WHITESPACE@29..30 " "
1027 TYPE_PRIMITIVE@30..33
1028 KW_U32@30..33 "u32"
1029 COMMA@33..34 ","
1030 PARAM@34..41
1031 WHITESPACE@34..35 " "
1032 IDENT@35..36 "b"
1033 COLON@36..37 ":"
1034 WHITESPACE@37..38 " "
1035 TYPE_PRIMITIVE@38..41
1036 KW_U32@38..41 "u32"
1037 R_PAREN@41..42 ")"
1038 WHITESPACE@42..43 " "
1039 ARROW@43..45 "->"
1040 WHITESPACE@45..46 " "
1041 TYPE_PRIMITIVE@46..49
1042 KW_U32@46..49 "u32"
1043 BLOCK@49..67
1044 WHITESPACE@49..50 " "
1045 L_BRACE@50..51 "{"
1046 WHITESPACE@51..52 " "
1047 RETURN_STMT@52..65
1048 KW_RETURN@52..58 "return"
1049 WHITESPACE@58..59 " "
1050 BINARY_EXPR@59..64
1051 PATH_EXPR@59..61
1052 IDENT@59..60 "a"
1053 WHITESPACE@60..61 " "
1054 PLUS@61..62 "+"
1055 WHITESPACE@62..63 " "
1056 PATH_EXPR@63..64
1057 IDENT@63..64 "b"
1058 SEMICOLON@64..65 ";"
1059 WHITESPACE@65..66 " "
1060 R_BRACE@66..67 "}"
1061 WHITESPACE@67..68 " "
1062 R_BRACE@68..69 "}"
1063 "#]]);
1064 }
1065
1066 #[test]
1067 fn parse_final_function() {
1068 check_file("program test.aleo { } final fn foo() { assert_eq(1u64, 1u64); }", expect![[r#"
1069 ROOT@0..63
1070 PROGRAM_DECL@0..21
1071 KW_PROGRAM@0..7 "program"
1072 WHITESPACE@7..8 " "
1073 IDENT@8..12 "test"
1074 DOT@12..13 "."
1075 KW_ALEO@13..17 "aleo"
1076 WHITESPACE@17..18 " "
1077 L_BRACE@18..19 "{"
1078 WHITESPACE@19..20 " "
1079 R_BRACE@20..21 "}"
1080 WHITESPACE@21..22 " "
1081 FINAL_FN_DEF@22..63
1082 KW_FINAL@22..27 "final"
1083 WHITESPACE@27..28 " "
1084 KW_FN@28..30 "fn"
1085 WHITESPACE@30..31 " "
1086 IDENT@31..34 "foo"
1087 PARAM_LIST@34..36
1088 L_PAREN@34..35 "("
1089 R_PAREN@35..36 ")"
1090 WHITESPACE@36..37 " "
1091 BLOCK@37..63
1092 L_BRACE@37..38 "{"
1093 WHITESPACE@38..39 " "
1094 ASSERT_EQ_STMT@39..61
1095 KW_ASSERT_EQ@39..48 "assert_eq"
1096 L_PAREN@48..49 "("
1097 LITERAL_INT@49..53
1098 INTEGER@49..53 "1u64"
1099 COMMA@53..54 ","
1100 WHITESPACE@54..55 " "
1101 LITERAL_INT@55..59
1102 INTEGER@55..59 "1u64"
1103 R_PAREN@59..60 ")"
1104 SEMICOLON@60..61 ";"
1105 WHITESPACE@61..62 " "
1106 R_BRACE@62..63 "}"
1107 "#]]);
1108 }
1109 #[test]
1114 fn parse_function_const_generic_single() {
1115 check_file_no_errors("program test.aleo { fn foo::[N: u32]() {} }");
1116 }
1117
1118 #[test]
1119 fn parse_function_const_generic_multi() {
1120 check_file_no_errors("program test.aleo { fn bar::[N: u32, M: u32](arr: u32) -> u32 { return 0u32; } }");
1121 }
1122
1123 #[test]
1124 fn parse_function_const_generic_empty() {
1125 check_file_no_errors("program test.aleo { fn baz::[]() {} }");
1126 }
1127
1128 #[test]
1129 fn parse_final_entry_const_generic() {
1130 check_file_no_errors("program test.aleo { fn t::[N: u32]() -> Final { return final {}; } }");
1131 }
1132
1133 #[test]
1134 fn parse_struct_const_generic() {
1135 check_file_no_errors("program test.aleo { struct Foo::[N: u32] { arr: u32, } }");
1136 }
1137
1138 #[test]
1139 fn parse_struct_const_generic_multi() {
1140 check_file_no_errors("program test.aleo { struct Matrix::[M: u32, N: u32] { data: u32, } }");
1141 }
1142
1143 #[test]
1144 fn parse_record_const_generic() {
1145 check_file_no_errors("program test.aleo { record Bar::[N: u32] { owner: address, } }");
1147 }
1148
1149 #[test]
1150 fn parse_transition() {
1151 check_file("program test.aleo { fn main(public x: u32) { } }", expect![[r#"
1152 ROOT@0..48
1153 PROGRAM_DECL@0..48
1154 KW_PROGRAM@0..7 "program"
1155 WHITESPACE@7..8 " "
1156 IDENT@8..12 "test"
1157 DOT@12..13 "."
1158 KW_ALEO@13..17 "aleo"
1159 WHITESPACE@17..18 " "
1160 L_BRACE@18..19 "{"
1161 FUNCTION_DEF@19..46
1162 WHITESPACE@19..20 " "
1163 KW_FN@20..22 "fn"
1164 WHITESPACE@22..23 " "
1165 IDENT@23..27 "main"
1166 PARAM_LIST@27..42
1167 L_PAREN@27..28 "("
1168 PARAM_PUBLIC@28..41
1169 KW_PUBLIC@28..34 "public"
1170 WHITESPACE@34..35 " "
1171 IDENT@35..36 "x"
1172 COLON@36..37 ":"
1173 WHITESPACE@37..38 " "
1174 TYPE_PRIMITIVE@38..41
1175 KW_U32@38..41 "u32"
1176 R_PAREN@41..42 ")"
1177 WHITESPACE@42..43 " "
1178 BLOCK@43..46
1179 L_BRACE@43..44 "{"
1180 WHITESPACE@44..45 " "
1181 R_BRACE@45..46 "}"
1182 WHITESPACE@46..47 " "
1183 R_BRACE@47..48 "}"
1184 "#]]);
1185 }
1186
1187 #[test]
1192 fn parse_record_visibility() {
1193 check_file("program test.aleo { record Token { public owner: address, private amount: u64, } }", expect![[
1194 r#"
1195 ROOT@0..82
1196 PROGRAM_DECL@0..82
1197 KW_PROGRAM@0..7 "program"
1198 WHITESPACE@7..8 " "
1199 IDENT@8..12 "test"
1200 DOT@12..13 "."
1201 KW_ALEO@13..17 "aleo"
1202 WHITESPACE@17..18 " "
1203 L_BRACE@18..19 "{"
1204 RECORD_DEF@19..80
1205 WHITESPACE@19..20 " "
1206 KW_RECORD@20..26 "record"
1207 WHITESPACE@26..27 " "
1208 IDENT@27..32 "Token"
1209 WHITESPACE@32..33 " "
1210 L_BRACE@33..34 "{"
1211 WHITESPACE@34..35 " "
1212 STRUCT_MEMBER_PUBLIC@35..56
1213 KW_PUBLIC@35..41 "public"
1214 WHITESPACE@41..42 " "
1215 IDENT@42..47 "owner"
1216 COLON@47..48 ":"
1217 WHITESPACE@48..49 " "
1218 TYPE_PRIMITIVE@49..56
1219 KW_ADDRESS@49..56 "address"
1220 COMMA@56..57 ","
1221 WHITESPACE@57..58 " "
1222 STRUCT_MEMBER_PRIVATE@58..77
1223 KW_PRIVATE@58..65 "private"
1224 WHITESPACE@65..66 " "
1225 IDENT@66..72 "amount"
1226 COLON@72..73 ":"
1227 WHITESPACE@73..74 " "
1228 TYPE_PRIMITIVE@74..77
1229 KW_U64@74..77 "u64"
1230 COMMA@77..78 ","
1231 WHITESPACE@78..79 " "
1232 R_BRACE@79..80 "}"
1233 WHITESPACE@80..81 " "
1234 R_BRACE@81..82 "}"
1235 "#
1236 ]]);
1237 }
1238
1239 #[test]
1244 fn parse_final_fn_with_return() {
1245 check_file("program test.aleo { final fn main(public x: u32) -> Final { return final {}; } }", expect![[r#"
1246 ROOT@0..80
1247 PROGRAM_DECL@0..80
1248 KW_PROGRAM@0..7 "program"
1249 WHITESPACE@7..8 " "
1250 IDENT@8..12 "test"
1251 DOT@12..13 "."
1252 KW_ALEO@13..17 "aleo"
1253 WHITESPACE@17..18 " "
1254 L_BRACE@18..19 "{"
1255 FINAL_FN_DEF@19..78
1256 WHITESPACE@19..20 " "
1257 KW_FINAL@20..25 "final"
1258 WHITESPACE@25..26 " "
1259 KW_FN@26..28 "fn"
1260 WHITESPACE@28..29 " "
1261 IDENT@29..33 "main"
1262 PARAM_LIST@33..48
1263 L_PAREN@33..34 "("
1264 PARAM_PUBLIC@34..47
1265 KW_PUBLIC@34..40 "public"
1266 WHITESPACE@40..41 " "
1267 IDENT@41..42 "x"
1268 COLON@42..43 ":"
1269 WHITESPACE@43..44 " "
1270 TYPE_PRIMITIVE@44..47
1271 KW_U32@44..47 "u32"
1272 R_PAREN@47..48 ")"
1273 WHITESPACE@48..49 " "
1274 ARROW@49..51 "->"
1275 WHITESPACE@51..52 " "
1276 TYPE_FINAL@52..58
1277 KW_FINAL_UPPER@52..57 "Final"
1278 WHITESPACE@57..58 " "
1279 BLOCK@58..78
1280 L_BRACE@58..59 "{"
1281 WHITESPACE@59..60 " "
1282 RETURN_STMT@60..76
1283 KW_RETURN@60..66 "return"
1284 WHITESPACE@66..67 " "
1285 FINAL_EXPR@67..75
1286 KW_FINAL@67..72 "final"
1287 WHITESPACE@72..73 " "
1288 BLOCK@73..75
1289 L_BRACE@73..74 "{"
1290 R_BRACE@74..75 "}"
1291 SEMICOLON@75..76 ";"
1292 WHITESPACE@76..77 " "
1293 R_BRACE@77..78 "}"
1294 WHITESPACE@78..79 " "
1295 R_BRACE@79..80 "}"
1296 "#]]);
1297 }
1298
1299 #[test]
1304 fn parse_function_return_tuple() {
1305 check_file(
1306 "program test.aleo { fn foo() -> (public u32, private field) { return (1u32, 2field); } }",
1307 expect![[r#"
1308 ROOT@0..88
1309 PROGRAM_DECL@0..88
1310 KW_PROGRAM@0..7 "program"
1311 WHITESPACE@7..8 " "
1312 IDENT@8..12 "test"
1313 DOT@12..13 "."
1314 KW_ALEO@13..17 "aleo"
1315 WHITESPACE@17..18 " "
1316 L_BRACE@18..19 "{"
1317 FUNCTION_DEF@19..86
1318 WHITESPACE@19..20 " "
1319 KW_FN@20..22 "fn"
1320 WHITESPACE@22..23 " "
1321 IDENT@23..26 "foo"
1322 PARAM_LIST@26..28
1323 L_PAREN@26..27 "("
1324 R_PAREN@27..28 ")"
1325 WHITESPACE@28..29 " "
1326 ARROW@29..31 "->"
1327 WHITESPACE@31..32 " "
1328 RETURN_TYPE@32..59
1329 L_PAREN@32..33 "("
1330 KW_PUBLIC@33..39 "public"
1331 WHITESPACE@39..40 " "
1332 TYPE_PRIMITIVE@40..43
1333 KW_U32@40..43 "u32"
1334 COMMA@43..44 ","
1335 WHITESPACE@44..45 " "
1336 KW_PRIVATE@45..52 "private"
1337 WHITESPACE@52..53 " "
1338 TYPE_PRIMITIVE@53..58
1339 KW_FIELD@53..58 "field"
1340 R_PAREN@58..59 ")"
1341 BLOCK@59..86
1342 WHITESPACE@59..60 " "
1343 L_BRACE@60..61 "{"
1344 WHITESPACE@61..62 " "
1345 RETURN_STMT@62..84
1346 KW_RETURN@62..68 "return"
1347 WHITESPACE@68..69 " "
1348 TUPLE_EXPR@69..83
1349 L_PAREN@69..70 "("
1350 LITERAL_INT@70..74
1351 INTEGER@70..74 "1u32"
1352 COMMA@74..75 ","
1353 WHITESPACE@75..76 " "
1354 LITERAL_FIELD@76..82
1355 INTEGER@76..82 "2field"
1356 R_PAREN@82..83 ")"
1357 SEMICOLON@83..84 ";"
1358 WHITESPACE@84..85 " "
1359 R_BRACE@85..86 "}"
1360 WHITESPACE@86..87 " "
1361 R_BRACE@87..88 "}"
1362 "#]],
1363 );
1364 }
1365
1366 #[test]
1371 fn parse_function_multi_annotation() {
1372 check_file("program test.aleo { @test @foo(k = \"v\") fn bar() { } }", expect![[r#"
1373 ROOT@0..54
1374 PROGRAM_DECL@0..54
1375 KW_PROGRAM@0..7 "program"
1376 WHITESPACE@7..8 " "
1377 IDENT@8..12 "test"
1378 DOT@12..13 "."
1379 KW_ALEO@13..17 "aleo"
1380 WHITESPACE@17..18 " "
1381 L_BRACE@18..19 "{"
1382 FUNCTION_DEF@19..52
1383 ANNOTATION@19..26
1384 WHITESPACE@19..20 " "
1385 AT@20..21 "@"
1386 IDENT@21..25 "test"
1387 WHITESPACE@25..26 " "
1388 ANNOTATION@26..39
1389 AT@26..27 "@"
1390 IDENT@27..30 "foo"
1391 L_PAREN@30..31 "("
1392 ANNOTATION_PAIR@31..38
1393 IDENT@31..32 "k"
1394 WHITESPACE@32..33 " "
1395 EQ@33..34 "="
1396 WHITESPACE@34..35 " "
1397 STRING@35..38 "\"v\""
1398 R_PAREN@38..39 ")"
1399 WHITESPACE@39..40 " "
1400 KW_FN@40..42 "fn"
1401 WHITESPACE@42..43 " "
1402 IDENT@43..46 "bar"
1403 PARAM_LIST@46..48
1404 L_PAREN@46..47 "("
1405 R_PAREN@47..48 ")"
1406 WHITESPACE@48..49 " "
1407 BLOCK@49..52
1408 L_BRACE@49..50 "{"
1409 WHITESPACE@50..51 " "
1410 R_BRACE@51..52 "}"
1411 WHITESPACE@52..53 " "
1412 R_BRACE@53..54 "}"
1413 "#]]);
1414 }
1415
1416 #[test]
1421 fn parse_storage() {
1422 check_file("program test.aleo { storage state: u64; }", expect![[r#"
1423 ROOT@0..41
1424 PROGRAM_DECL@0..41
1425 KW_PROGRAM@0..7 "program"
1426 WHITESPACE@7..8 " "
1427 IDENT@8..12 "test"
1428 DOT@12..13 "."
1429 KW_ALEO@13..17 "aleo"
1430 WHITESPACE@17..18 " "
1431 L_BRACE@18..19 "{"
1432 STORAGE_DEF@19..39
1433 WHITESPACE@19..20 " "
1434 KW_STORAGE@20..27 "storage"
1435 WHITESPACE@27..28 " "
1436 IDENT@28..33 "state"
1437 COLON@33..34 ":"
1438 WHITESPACE@34..35 " "
1439 TYPE_PRIMITIVE@35..38
1440 KW_U64@35..38 "u64"
1441 SEMICOLON@38..39 ";"
1442 WHITESPACE@39..40 " "
1443 R_BRACE@40..41 "}"
1444 "#]]);
1445 }
1446
1447 #[test]
1452 fn parse_script_rejected() {
1453 check_file("program test.aleo { script main() { } }", expect![[r#"
1454 ROOT@0..39
1455 PROGRAM_DECL@0..39
1456 KW_PROGRAM@0..7 "program"
1457 WHITESPACE@7..8 " "
1458 IDENT@8..12 "test"
1459 DOT@12..13 "."
1460 KW_ALEO@13..17 "aleo"
1461 WHITESPACE@17..18 " "
1462 L_BRACE@18..19 "{"
1463 WHITESPACE@19..20 " "
1464 KW_SCRIPT@20..26 "script"
1465 ERROR@26..37
1466 WHITESPACE@26..27 " "
1467 IDENT@27..31 "main"
1468 L_PAREN@31..32 "("
1469 R_PAREN@32..33 ")"
1470 WHITESPACE@33..34 " "
1471 L_BRACE@34..35 "{"
1472 WHITESPACE@35..36 " "
1473 R_BRACE@36..37 "}"
1474 WHITESPACE@37..38 " "
1475 R_BRACE@38..39 "}"
1476 "#]]);
1477 }
1478
1479 #[test]
1484 fn parse_program_with_items() {
1485 check_file("program test.aleo { struct Foo { x: u32, } fn bar() -> u32 { return 1u32; } }", expect![[r#"
1486 ROOT@0..77
1487 PROGRAM_DECL@0..77
1488 KW_PROGRAM@0..7 "program"
1489 WHITESPACE@7..8 " "
1490 IDENT@8..12 "test"
1491 DOT@12..13 "."
1492 KW_ALEO@13..17 "aleo"
1493 WHITESPACE@17..18 " "
1494 L_BRACE@18..19 "{"
1495 STRUCT_DEF@19..42
1496 WHITESPACE@19..20 " "
1497 KW_STRUCT@20..26 "struct"
1498 WHITESPACE@26..27 " "
1499 IDENT@27..30 "Foo"
1500 WHITESPACE@30..31 " "
1501 L_BRACE@31..32 "{"
1502 WHITESPACE@32..33 " "
1503 STRUCT_MEMBER@33..39
1504 IDENT@33..34 "x"
1505 COLON@34..35 ":"
1506 WHITESPACE@35..36 " "
1507 TYPE_PRIMITIVE@36..39
1508 KW_U32@36..39 "u32"
1509 COMMA@39..40 ","
1510 WHITESPACE@40..41 " "
1511 R_BRACE@41..42 "}"
1512 FUNCTION_DEF@42..75
1513 WHITESPACE@42..43 " "
1514 KW_FN@43..45 "fn"
1515 WHITESPACE@45..46 " "
1516 IDENT@46..49 "bar"
1517 PARAM_LIST@49..51
1518 L_PAREN@49..50 "("
1519 R_PAREN@50..51 ")"
1520 WHITESPACE@51..52 " "
1521 ARROW@52..54 "->"
1522 WHITESPACE@54..55 " "
1523 TYPE_PRIMITIVE@55..58
1524 KW_U32@55..58 "u32"
1525 BLOCK@58..75
1526 WHITESPACE@58..59 " "
1527 L_BRACE@59..60 "{"
1528 WHITESPACE@60..61 " "
1529 RETURN_STMT@61..73
1530 KW_RETURN@61..67 "return"
1531 WHITESPACE@67..68 " "
1532 LITERAL_INT@68..72
1533 INTEGER@68..72 "1u32"
1534 SEMICOLON@72..73 ";"
1535 WHITESPACE@73..74 " "
1536 R_BRACE@74..75 "}"
1537 WHITESPACE@75..76 " "
1538 R_BRACE@76..77 "}"
1539 "#]]);
1540 }
1541
1542 #[test]
1547 fn parse_import_invalid_network() {
1548 check_file("import foo.bar;", expect![[r#"
1552 ROOT@0..15
1553 IMPORT@0..15
1554 KW_IMPORT@0..6 "import"
1555 WHITESPACE@6..7 " "
1556 IDENT@7..10 "foo"
1557 DOT@10..11 "."
1558 IDENT@11..14 "bar"
1559 SEMICOLON@14..15 ";"
1560 "#]]);
1561 }
1562
1563 #[test]
1568 fn parse_annotation_space_after_at() {
1569 let (tokens, _) = lex("program test.aleo { @ test fn foo() { } }");
1571 let mut parser = Parser::new("program test.aleo { @ test fn foo() { } }", &tokens);
1572 let root = parser.start();
1573 parser.parse_file_items();
1574 root.complete(&mut parser, ROOT);
1575 let parse: Parse = parser.finish(vec![]);
1576 assert!(!parse.errors().is_empty(), "expected error for space after @, got none");
1577 }
1578}