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_EXPORT, 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_EXPORT | KW_CONST | KW_STRUCT | KW_FN | KW_FINAL | AT | KW_INTERFACE | KW_VIEW => {
116 if self.parse_module_item().is_none() {
117 self.error_and_bump("expected module item");
118 }
119 }
120 _ => {
121 self.error("expected `import`, `program`, or module item at top level");
122 self.recover(&[
123 KW_IMPORT,
124 KW_PROGRAM,
125 KW_EXPORT,
126 KW_CONST,
127 KW_STRUCT,
128 KW_FN,
129 KW_FINAL,
130 KW_VIEW,
131 KW_INTERFACE,
132 AT,
133 ]);
134 }
135 }
136 }
137 }
138
139 pub fn parse_module_items(&mut self) {
144 loop {
145 self.skip_trivia();
146 if self.at_eof() {
147 break;
148 }
149
150 self.erroring = false;
152
153 if self.parse_module_item().is_none() {
154 self.error("expected `const`, `struct`, or `fn` in module");
155 self.recover(Self::MODULE_ITEM_RECOVERY);
156 }
157 }
158 }
159
160 fn parse_module_item(&mut self) -> Option<CompletedMarker> {
165 let head = if self.at(KW_EXPORT) { self.nth(1) } else { self.current() };
167 match head {
168 KW_CONST => self.parse_global_const(),
169 KW_STRUCT => self.parse_composite_def(STRUCT_DEF),
170 KW_INTERFACE => self.parse_interface_def(),
171 AT | KW_FN | KW_FINAL | KW_VIEW => self.parse_function_or_constructor(false),
172 _ => {
173 if self.at(KW_EXPORT) {
174 self.error("expected `fn`, `struct`, `const`, or `interface` after `export`");
175 self.bump_any();
176 }
177 None
178 }
179 }
180 }
181
182 fn parse_import(&mut self) -> Option<CompletedMarker> {
184 let m = self.start();
185 self.bump_any(); self.parse_program_id();
189
190 self.expect(SEMICOLON);
191 Some(m.complete(self, IMPORT))
192 }
193
194 fn parse_program_decl(&mut self) -> Option<CompletedMarker> {
196 let m = self.start();
197 self.bump_any(); self.parse_program_id();
201
202 self.skip_trivia();
203 if self.eat(COLON) {
205 self.skip_trivia();
206 self.erroring = false;
208 self.parse_parent_list();
209 }
210
211 self.expect(L_BRACE);
212
213 while !self.at(R_BRACE) && !self.at_eof() {
215 self.erroring = false;
217 if self.parse_program_item().is_none() {
218 self.recover(ITEM_RECOVERY);
220 }
221 }
222
223 self.expect(R_BRACE);
224 Some(m.complete(self, PROGRAM_DECL))
225 }
226
227 fn parse_program_id(&mut self) {
229 self.skip_trivia();
230 if self.at(IDENT) {
231 self.bump_any(); self.expect(DOT);
233 if !self.eat(KW_ALEO) {
234 if self.at(IDENT) {
235 self.bump_any();
238 } else {
239 self.error("expected 'aleo'");
240 }
241 }
242 } else {
243 self.error("expected program name");
244 }
245 }
246
247 fn parse_program_item(&mut self) -> Option<CompletedMarker> {
252 if self.at(KW_EXPORT) {
253 self.error("`export` is not allowed inside a `program` block; items here are implicitly public");
254 self.bump_any();
255 }
256 match self.current() {
260 AT => self.parse_function_or_constructor(true),
261 KW_STRUCT => self.parse_composite_def(STRUCT_DEF),
262 KW_RECORD => self.parse_composite_def(RECORD_DEF),
263 KW_MAPPING => self.parse_mapping_def(),
264 KW_STORAGE => self.parse_storage_def(),
265 KW_CONST => self.parse_global_const(),
266 KW_FN | KW_FINAL | KW_VIEW | KW_CONSTRUCTOR => self.parse_function_or_constructor(true),
267 KW_SCRIPT => {
268 self.error("'script' functions are no longer supported; use @test on entry point functions instead");
269 self.bump_any();
270 None
271 }
272 KW_INTERFACE => self.parse_interface_def(),
273 _ => {
274 let expected: Vec<&str> = Self::PROGRAM_ITEM_EXPECTED.iter().map(|k| k.user_friendly_name()).collect();
275 self.error_unexpected(self.current(), &expected);
276 None
277 }
278 }
279 }
280
281 fn parse_annotation(&mut self) {
283 let m = self.start();
284 self.bump_any(); if self.current_including_trivia().is_trivia() {
288 self.error_unexpected(self.current(), &["an identifier", "'program'"]);
289 self.skip_trivia();
290 if self.at(IDENT) || self.current().is_keyword() {
292 self.bump_any();
293 }
294 } else if self.at(IDENT) || self.current().is_keyword() {
295 self.bump_any();
298 } else {
299 self.error("expected annotation name");
300 }
301
302 if self.eat(L_PAREN) {
305 if !self.at(R_PAREN) {
306 self.parse_annotation_member();
307 while self.eat(COMMA) {
308 if self.at(R_PAREN) {
309 break;
310 }
311 self.erroring = false;
313 self.parse_annotation_member();
314 }
315 }
316 if !self.at(R_PAREN) && !self.at_eof() {
318 self.error_unexpected(self.current(), &["')'", "','"]);
319 while !self.at(R_PAREN) && !self.at_eof() {
321 self.bump_any();
322 }
323 }
324 self.expect(R_PAREN);
325 }
326
327 m.complete(self, ANNOTATION);
328 }
329
330 fn parse_annotation_member(&mut self) {
332 let m = self.start();
333 if self.at(IDENT) || self.at(KW_ADDRESS) || self.at(KW_MAPPING) {
335 self.bump_any();
336 } else {
337 self.error_unexpected(self.current(), &["an identifier", "')'", "'address", "'mapping'"]);
338 while !self.at(COMMA) && !self.at(R_PAREN) && !self.at_eof() {
340 self.bump_any();
341 }
342 m.abandon(self);
343 return;
344 }
345 self.expect(EQ);
346 if self.at(STRING) {
347 self.bump_any();
348 } else {
349 self.error("expected string literal for annotation value");
350 }
351 m.complete(self, ANNOTATION_PAIR);
352 }
353
354 fn parse_composite_def(&mut self, kind: SyntaxKind) -> Option<CompletedMarker> {
356 let m = self.start();
357 let _ = self.eat(KW_EXPORT);
358 let label = if kind == STRUCT_DEF { "struct" } else { "record" };
359 self.bump_any(); self.skip_trivia();
363 if self.at(IDENT) {
364 self.bump_any();
365 } else {
366 self.error(format!("expected {label} name"));
367 self.recover(Self::STRUCT_NAME_RECOVERY);
368 return Some(m.complete(self, ERROR));
369 }
370
371 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
373 self.bump_any(); self.parse_const_param_list();
375 }
376
377 self.expect(L_BRACE);
379 self.parse_struct_fields_until(&[R_BRACE]);
380 self.expect(R_BRACE);
381
382 Some(m.complete(self, kind))
383 }
384
385 fn parse_struct_fields_until(&mut self, closing_symbols: &[SyntaxKind]) {
387 while !closing_symbols.iter().any(|closing| self.at(*closing)) && !self.at_eof() {
388 self.skip_trivia();
390 let m = self.start();
391
392 let vis = self.eat_visibility();
394
395 self.skip_trivia();
397 if self.at(IDENT) {
398 self.bump_any();
399 } else {
400 m.abandon(self);
401 if !closing_symbols.iter().any(|closing| self.at(*closing)) {
403 self.error_recover("expected field name", Self::FIELD_RECOVERY);
404 }
405 if self.eat(COMMA) {
407 continue;
408 }
409 break;
410 }
411
412 self.expect(COLON);
414 if self.parse_type().is_none() {
415 self.error_recover("expected type", Self::FIELD_RECOVERY);
416 }
417
418 let kind = match vis {
419 Some(KW_PUBLIC) => STRUCT_MEMBER_PUBLIC,
420 Some(KW_PRIVATE) => STRUCT_MEMBER_PRIVATE,
421 Some(KW_CONSTANT) => STRUCT_MEMBER_CONSTANT,
422 _ => STRUCT_MEMBER,
423 };
424 m.complete(self, kind);
425
426 if !self.eat(COMMA) {
428 if !closing_symbols.iter().any(|closing| self.at(*closing)) && !self.at_eof() {
432 self.error("expected ','");
433 self.erroring = false;
435 }
436 }
437 }
438 }
439
440 fn parse_mapping_def(&mut self) -> Option<CompletedMarker> {
442 let m = self.start();
443 self.bump_any(); self.skip_trivia();
447 if self.at(IDENT) {
448 self.bump_any();
449 } else {
450 self.error("expected mapping name");
451 }
452
453 self.expect(COLON);
455 if self.parse_type().is_none() {
456 self.error_recover("expected key type", TYPE_RECOVERY);
457 }
458 self.expect(FAT_ARROW);
459 if self.parse_type().is_none() {
460 self.error_recover("expected value type", TYPE_RECOVERY);
461 }
462
463 self.expect(SEMICOLON);
464 Some(m.complete(self, MAPPING_DEF))
465 }
466
467 fn parse_storage_def(&mut self) -> Option<CompletedMarker> {
469 let m = self.start();
470 self.bump_any(); self.skip_trivia();
474 if self.at(IDENT) {
475 self.bump_any();
476 } else {
477 self.error("expected storage name");
478 }
479
480 self.expect(COLON);
482 if self.parse_type().is_none() {
483 self.error_recover("expected type", TYPE_RECOVERY);
484 }
485
486 self.expect(SEMICOLON);
487 Some(m.complete(self, STORAGE_DEF))
488 }
489
490 fn parse_global_const(&mut self) -> Option<CompletedMarker> {
492 let m = self.start();
493 let _ = self.eat(KW_EXPORT);
494 self.bump_any(); self.skip_trivia();
498 if self.at(IDENT) {
499 self.bump_any();
500 } else {
501 self.error("expected constant name");
502 self.recover(&[SEMICOLON]);
503 self.eat(SEMICOLON);
504 return Some(m.complete(self, GLOBAL_CONST));
505 }
506
507 self.expect(COLON);
509 if self.parse_type().is_none() {
510 self.error_recover("expected type", TYPE_RECOVERY);
511 }
512
513 self.expect(EQ);
515 if self.parse_expr().is_none() {
516 self.error_recover("expected expression", EXPR_RECOVERY);
517 }
518
519 self.expect(SEMICOLON);
520 Some(m.complete(self, GLOBAL_CONST))
521 }
522
523 fn parse_function_or_constructor(&mut self, in_program_block: bool) -> Option<CompletedMarker> {
531 let m = self.start();
532
533 while self.at(AT) {
535 self.parse_annotation();
536 }
537
538 if self.at(KW_EXPORT) {
539 if in_program_block {
540 self.error("`export` is not allowed inside a `program` block; items here are implicitly public");
541 }
542 self.bump_any();
543 }
544
545 let ate_final = self.eat(KW_FINAL);
549 let ate_view = if ate_final && self.at(KW_VIEW) {
550 self.error("`final` and `view` cannot be combined");
551 self.bump_any();
552 false
553 } else {
554 self.eat(KW_VIEW)
555 };
556
557 match self.current() {
559 KW_FN => {
560 self.parse_function_body();
561 let kind = match (ate_final, ate_view) {
562 (true, _) => FINAL_FN_DEF,
563 (false, true) => VIEW_FN_DEF,
564 (false, false) => FUNCTION_DEF,
565 };
566 Some(m.complete(self, kind))
567 }
568 KW_CONSTRUCTOR => {
569 self.parse_constructor_body();
570 Some(m.complete(self, CONSTRUCTOR_DEF))
571 }
572 _ => {
573 self.error("expected 'fn' or 'constructor'");
574 m.abandon(self);
575 None
576 }
577 }
578 }
579
580 fn parse_function_body(&mut self) {
582 if !self.eat(KW_FN) {
584 self.error("expected 'fn'");
585 }
586
587 self.skip_trivia();
589 if self.at(IDENT) {
590 self.bump_any();
591 } else {
592 self.error("expected function name");
593 }
594
595 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
597 self.bump_any(); self.parse_const_param_list();
599 }
600
601 self.parse_param_list();
603
604 if self.eat(ARROW) {
606 self.parse_return_type();
607 }
608
609 self.parse_block();
611 }
612
613 fn parse_return_type(&mut self) {
619 self.skip_trivia();
620 if self.at(L_PAREN) {
621 let m = self.start();
623 self.bump_any(); if !self.at(R_PAREN) {
625 self.eat_visibility();
627 if self.parse_type().is_none() {
628 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
629 }
630 while self.eat(COMMA) {
631 if self.at(R_PAREN) {
632 break;
633 }
634 self.eat_visibility();
635 if self.parse_type().is_none() {
636 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
637 }
638 }
639 }
640 self.expect(R_PAREN);
641 m.complete(self, RETURN_TYPE);
642 } else {
643 self.eat_visibility();
645 if self.parse_type().is_none() {
646 self.error_recover("expected return type", Self::RETURN_TYPE_RECOVERY);
647 }
648 }
649 }
650
651 fn parse_constructor_body(&mut self) {
653 self.bump_any(); self.parse_param_list();
657
658 self.parse_block();
660 }
661
662 fn parse_param_list(&mut self) {
664 let m = self.start();
665 self.expect(L_PAREN);
666
667 while !self.at(R_PAREN) && !self.at_eof() {
668 self.erroring = false;
670 self.parse_param();
671 if !self.eat(COMMA) {
672 break;
673 }
674 }
675
676 self.expect(R_PAREN);
677 m.complete(self, PARAM_LIST);
678 }
679
680 fn parse_parent_list(&mut self) {
682 let m = self.start();
683 self.parse_type();
684 self.skip_trivia();
685
686 while self.at(PLUS) && !self.at_eof() {
687 self.bump_any(); self.skip_trivia();
689 self.parse_type();
690 self.skip_trivia();
691 }
692
693 m.complete(self, PARENT_LIST);
694 }
695
696 fn parse_param(&mut self) {
698 let m = self.start();
699 self.skip_trivia();
700
701 let vis = self.eat_visibility();
703
704 self.skip_trivia();
706 if self.at(IDENT) {
707 self.bump_any();
708 } else {
709 self.error("expected parameter name");
710 }
711
712 self.expect(COLON);
714 if self.parse_type().is_none() {
715 self.error_recover("expected parameter type", PARAM_RECOVERY);
716 }
717
718 let kind = match vis {
719 Some(KW_PUBLIC) => PARAM_PUBLIC,
720 Some(KW_PRIVATE) => PARAM_PRIVATE,
721 Some(KW_CONSTANT) => PARAM_CONSTANT,
722 _ => PARAM,
723 };
724 m.complete(self, kind);
725 }
726
727 fn parse_interface_def(&mut self) -> Option<CompletedMarker> {
733 let m = self.start();
734 let _ = self.eat(KW_EXPORT);
735 self.bump_any(); self.skip_trivia();
739 if self.at(IDENT) {
740 self.bump_any();
741 } else {
742 self.error("expected parameter name");
743 }
744
745 self.skip_trivia();
747 if self.eat(COLON) {
748 self.skip_trivia();
749 self.parse_parent_list();
750 }
751
752 self.expect(L_BRACE);
754 while !self.at(R_BRACE) && !self.at_eof() {
755 self.erroring = false;
756 if !self.parse_interface_item() {
757 self.error_and_bump("expected function or record prototype");
758 }
759 }
760 self.expect(R_BRACE);
761
762 Some(m.complete(self, INTERFACE_DEF))
763 }
764
765 fn parse_interface_item(&mut self) -> bool {
767 match self.current() {
768 KW_FN | KW_VIEW => {
769 self.parse_fn_prototype();
770 true
771 }
772 KW_RECORD => {
773 self.parse_record_prototype();
774 true
775 }
776 KW_MAPPING => {
777 self.parse_mapping_def();
778 true
779 }
780 KW_STORAGE => {
781 self.parse_storage_def();
782 true
783 }
784 _ => false,
785 }
786 }
787
788 fn parse_fn_prototype(&mut self) -> Option<CompletedMarker> {
793 let m = self.start();
794 let _ = self.eat(KW_VIEW);
795 self.bump_any(); self.skip_trivia();
799 if self.at(IDENT) {
800 self.bump_any();
801 } else {
802 self.error("expected function name");
803 }
804
805 if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
807 self.bump_any(); self.parse_const_param_list();
809 }
810
811 self.parse_param_list();
813
814 if self.eat(ARROW) {
816 self.parse_return_type();
817 }
818
819 self.expect(SEMICOLON);
820 Some(m.complete(self, FN_PROTOTYPE_DEF))
821 }
822
823 fn parse_record_prototype(&mut self) -> Option<CompletedMarker> {
825 let m = self.start();
826 self.bump_any(); self.skip_trivia();
829 if self.at(IDENT) {
830 self.bump_any();
831 } else {
832 self.error("expected record name");
833 }
834
835 if self.at(SEMICOLON) {
836 self.bump_any();
838 } else {
839 self.expect(L_BRACE);
841 self.parse_struct_fields_until(&[DOT_DOT, R_BRACE]);
842 if self.eat(DOT_DOT) {
843 self.expect(R_BRACE);
844 } else {
845 self.error("expected `..`; fully constraining record fields in interfaces is not yet supported");
846 self.expect(R_BRACE);
847 }
848 }
849
850 Some(m.complete(self, RECORD_PROTOTYPE_DEF))
851 }
852}
853
854#[cfg(test)]
855mod tests {
856 use super::*;
857 use crate::{lexer::lex, parser::Parse};
858 use expect_test::{Expect, expect};
859
860 fn check_file(input: &str, expect: Expect) {
861 let (tokens, _) = lex(input);
862 let mut parser = Parser::new(input, &tokens);
863 let root = parser.start();
864 parser.parse_file_items();
865 root.complete(&mut parser, ROOT);
866 let parse: Parse = parser.finish(vec![]);
867 let output = format!("{:#?}", parse.syntax());
868 expect.assert_eq(&output);
869 }
870
871 fn check_file_no_errors(input: &str) {
872 let (tokens, _) = lex(input);
873 let mut parser = Parser::new(input, &tokens);
874 let root = parser.start();
875 parser.parse_file_items();
876 root.complete(&mut parser, ROOT);
877 let parse: Parse = parser.finish(vec![]);
878 if !parse.errors().is_empty() {
879 for err in parse.errors() {
880 eprintln!("error at {:?}: {}", err.range, err.message);
881 }
882 eprintln!("tree:\n{:#?}", parse.syntax());
883 panic!("parse had {} error(s)", parse.errors().len());
884 }
885 }
886
887 #[test]
892 fn parse_import() {
893 check_file("import credits.aleo;", expect![[r#"
894 ROOT@0..20
895 IMPORT@0..20
896 KW_IMPORT@0..6 "import"
897 WHITESPACE@6..7 " "
898 IDENT@7..14 "credits"
899 DOT@14..15 "."
900 KW_ALEO@15..19 "aleo"
901 SEMICOLON@19..20 ";"
902 "#]]);
903 }
904
905 #[test]
910 fn parse_program_empty() {
911 check_file("program test.aleo { }", expect![[r#"
912 ROOT@0..21
913 PROGRAM_DECL@0..21
914 KW_PROGRAM@0..7 "program"
915 WHITESPACE@7..8 " "
916 IDENT@8..12 "test"
917 DOT@12..13 "."
918 KW_ALEO@13..17 "aleo"
919 WHITESPACE@17..18 " "
920 L_BRACE@18..19 "{"
921 WHITESPACE@19..20 " "
922 R_BRACE@20..21 "}"
923 "#]]);
924 }
925
926 #[test]
931 fn parse_struct() {
932 check_file("program test.aleo { struct Point { x: u32, y: u32 } }", expect![[r#"
933 ROOT@0..53
934 PROGRAM_DECL@0..53
935 KW_PROGRAM@0..7 "program"
936 WHITESPACE@7..8 " "
937 IDENT@8..12 "test"
938 DOT@12..13 "."
939 KW_ALEO@13..17 "aleo"
940 WHITESPACE@17..18 " "
941 L_BRACE@18..19 "{"
942 STRUCT_DEF@19..51
943 WHITESPACE@19..20 " "
944 KW_STRUCT@20..26 "struct"
945 WHITESPACE@26..27 " "
946 IDENT@27..32 "Point"
947 WHITESPACE@32..33 " "
948 L_BRACE@33..34 "{"
949 WHITESPACE@34..35 " "
950 STRUCT_MEMBER@35..41
951 IDENT@35..36 "x"
952 COLON@36..37 ":"
953 WHITESPACE@37..38 " "
954 TYPE_PRIMITIVE@38..41
955 KW_U32@38..41 "u32"
956 COMMA@41..42 ","
957 WHITESPACE@42..43 " "
958 STRUCT_MEMBER@43..49
959 IDENT@43..44 "y"
960 COLON@44..45 ":"
961 WHITESPACE@45..46 " "
962 TYPE_PRIMITIVE@46..49
963 KW_U32@46..49 "u32"
964 WHITESPACE@49..50 " "
965 R_BRACE@50..51 "}"
966 WHITESPACE@51..52 " "
967 R_BRACE@52..53 "}"
968 "#]]);
969 }
970
971 #[test]
976 fn parse_record() {
977 check_file("program test.aleo { record Token { owner: address, amount: u64 } }", expect![[r#"
978 ROOT@0..66
979 PROGRAM_DECL@0..66
980 KW_PROGRAM@0..7 "program"
981 WHITESPACE@7..8 " "
982 IDENT@8..12 "test"
983 DOT@12..13 "."
984 KW_ALEO@13..17 "aleo"
985 WHITESPACE@17..18 " "
986 L_BRACE@18..19 "{"
987 RECORD_DEF@19..64
988 WHITESPACE@19..20 " "
989 KW_RECORD@20..26 "record"
990 WHITESPACE@26..27 " "
991 IDENT@27..32 "Token"
992 WHITESPACE@32..33 " "
993 L_BRACE@33..34 "{"
994 WHITESPACE@34..35 " "
995 STRUCT_MEMBER@35..49
996 IDENT@35..40 "owner"
997 COLON@40..41 ":"
998 WHITESPACE@41..42 " "
999 TYPE_PRIMITIVE@42..49
1000 KW_ADDRESS@42..49 "address"
1001 COMMA@49..50 ","
1002 WHITESPACE@50..51 " "
1003 STRUCT_MEMBER@51..62
1004 IDENT@51..57 "amount"
1005 COLON@57..58 ":"
1006 WHITESPACE@58..59 " "
1007 TYPE_PRIMITIVE@59..62
1008 KW_U64@59..62 "u64"
1009 WHITESPACE@62..63 " "
1010 R_BRACE@63..64 "}"
1011 WHITESPACE@64..65 " "
1012 R_BRACE@65..66 "}"
1013 "#]]);
1014 }
1015
1016 #[test]
1021 fn parse_mapping() {
1022 check_file("program test.aleo { mapping balances: address => u64; }", expect![[r#"
1023 ROOT@0..55
1024 PROGRAM_DECL@0..55
1025 KW_PROGRAM@0..7 "program"
1026 WHITESPACE@7..8 " "
1027 IDENT@8..12 "test"
1028 DOT@12..13 "."
1029 KW_ALEO@13..17 "aleo"
1030 WHITESPACE@17..18 " "
1031 L_BRACE@18..19 "{"
1032 MAPPING_DEF@19..53
1033 WHITESPACE@19..20 " "
1034 KW_MAPPING@20..27 "mapping"
1035 WHITESPACE@27..28 " "
1036 IDENT@28..36 "balances"
1037 COLON@36..37 ":"
1038 WHITESPACE@37..38 " "
1039 TYPE_PRIMITIVE@38..45
1040 KW_ADDRESS@38..45 "address"
1041 WHITESPACE@45..46 " "
1042 FAT_ARROW@46..48 "=>"
1043 WHITESPACE@48..49 " "
1044 TYPE_PRIMITIVE@49..52
1045 KW_U64@49..52 "u64"
1046 SEMICOLON@52..53 ";"
1047 WHITESPACE@53..54 " "
1048 R_BRACE@54..55 "}"
1049 "#]]);
1050 }
1051
1052 #[test]
1057 fn parse_function() {
1058 check_file("program test.aleo { fn add(a: u32, b: u32) -> u32 { return a + b; } }", expect![[r#"
1059 ROOT@0..69
1060 PROGRAM_DECL@0..69
1061 KW_PROGRAM@0..7 "program"
1062 WHITESPACE@7..8 " "
1063 IDENT@8..12 "test"
1064 DOT@12..13 "."
1065 KW_ALEO@13..17 "aleo"
1066 WHITESPACE@17..18 " "
1067 L_BRACE@18..19 "{"
1068 FUNCTION_DEF@19..67
1069 WHITESPACE@19..20 " "
1070 KW_FN@20..22 "fn"
1071 WHITESPACE@22..23 " "
1072 IDENT@23..26 "add"
1073 PARAM_LIST@26..42
1074 L_PAREN@26..27 "("
1075 PARAM@27..33
1076 IDENT@27..28 "a"
1077 COLON@28..29 ":"
1078 WHITESPACE@29..30 " "
1079 TYPE_PRIMITIVE@30..33
1080 KW_U32@30..33 "u32"
1081 COMMA@33..34 ","
1082 PARAM@34..41
1083 WHITESPACE@34..35 " "
1084 IDENT@35..36 "b"
1085 COLON@36..37 ":"
1086 WHITESPACE@37..38 " "
1087 TYPE_PRIMITIVE@38..41
1088 KW_U32@38..41 "u32"
1089 R_PAREN@41..42 ")"
1090 WHITESPACE@42..43 " "
1091 ARROW@43..45 "->"
1092 WHITESPACE@45..46 " "
1093 TYPE_PRIMITIVE@46..49
1094 KW_U32@46..49 "u32"
1095 BLOCK@49..67
1096 WHITESPACE@49..50 " "
1097 L_BRACE@50..51 "{"
1098 WHITESPACE@51..52 " "
1099 RETURN_STMT@52..65
1100 KW_RETURN@52..58 "return"
1101 WHITESPACE@58..59 " "
1102 BINARY_EXPR@59..64
1103 PATH_EXPR@59..61
1104 IDENT@59..60 "a"
1105 WHITESPACE@60..61 " "
1106 PLUS@61..62 "+"
1107 WHITESPACE@62..63 " "
1108 PATH_EXPR@63..64
1109 IDENT@63..64 "b"
1110 SEMICOLON@64..65 ";"
1111 WHITESPACE@65..66 " "
1112 R_BRACE@66..67 "}"
1113 WHITESPACE@67..68 " "
1114 R_BRACE@68..69 "}"
1115 "#]]);
1116 }
1117
1118 #[test]
1119 fn parse_final_function() {
1120 check_file("program test.aleo { } final fn foo() { assert_eq(1u64, 1u64); }", expect![[r#"
1121 ROOT@0..63
1122 PROGRAM_DECL@0..21
1123 KW_PROGRAM@0..7 "program"
1124 WHITESPACE@7..8 " "
1125 IDENT@8..12 "test"
1126 DOT@12..13 "."
1127 KW_ALEO@13..17 "aleo"
1128 WHITESPACE@17..18 " "
1129 L_BRACE@18..19 "{"
1130 WHITESPACE@19..20 " "
1131 R_BRACE@20..21 "}"
1132 WHITESPACE@21..22 " "
1133 FINAL_FN_DEF@22..63
1134 KW_FINAL@22..27 "final"
1135 WHITESPACE@27..28 " "
1136 KW_FN@28..30 "fn"
1137 WHITESPACE@30..31 " "
1138 IDENT@31..34 "foo"
1139 PARAM_LIST@34..36
1140 L_PAREN@34..35 "("
1141 R_PAREN@35..36 ")"
1142 WHITESPACE@36..37 " "
1143 BLOCK@37..63
1144 L_BRACE@37..38 "{"
1145 WHITESPACE@38..39 " "
1146 ASSERT_EQ_STMT@39..61
1147 KW_ASSERT_EQ@39..48 "assert_eq"
1148 L_PAREN@48..49 "("
1149 LITERAL_INT@49..53
1150 INTEGER@49..53 "1u64"
1151 COMMA@53..54 ","
1152 WHITESPACE@54..55 " "
1153 LITERAL_INT@55..59
1154 INTEGER@55..59 "1u64"
1155 R_PAREN@59..60 ")"
1156 SEMICOLON@60..61 ";"
1157 WHITESPACE@61..62 " "
1158 R_BRACE@62..63 "}"
1159 "#]]);
1160 }
1161 #[test]
1166 fn parse_view_function() {
1167 check_file_no_errors(
1168 "program test.aleo { mapping balances: address => u64; view fn balance_of(addr: address) -> u64 { return 0u64; } }",
1169 );
1170 }
1171
1172 #[test]
1173 fn parse_view_uses_view_node_kind() {
1174 check_file("program test.aleo { view fn q() -> u64 { return 0u64; } }", expect![[r#"
1175 ROOT@0..57
1176 PROGRAM_DECL@0..57
1177 KW_PROGRAM@0..7 "program"
1178 WHITESPACE@7..8 " "
1179 IDENT@8..12 "test"
1180 DOT@12..13 "."
1181 KW_ALEO@13..17 "aleo"
1182 WHITESPACE@17..18 " "
1183 L_BRACE@18..19 "{"
1184 VIEW_FN_DEF@19..55
1185 WHITESPACE@19..20 " "
1186 KW_VIEW@20..24 "view"
1187 WHITESPACE@24..25 " "
1188 KW_FN@25..27 "fn"
1189 WHITESPACE@27..28 " "
1190 IDENT@28..29 "q"
1191 PARAM_LIST@29..31
1192 L_PAREN@29..30 "("
1193 R_PAREN@30..31 ")"
1194 WHITESPACE@31..32 " "
1195 ARROW@32..34 "->"
1196 WHITESPACE@34..35 " "
1197 TYPE_PRIMITIVE@35..38
1198 KW_U64@35..38 "u64"
1199 BLOCK@38..55
1200 WHITESPACE@38..39 " "
1201 L_BRACE@39..40 "{"
1202 WHITESPACE@40..41 " "
1203 RETURN_STMT@41..53
1204 KW_RETURN@41..47 "return"
1205 WHITESPACE@47..48 " "
1206 LITERAL_INT@48..52
1207 INTEGER@48..52 "0u64"
1208 SEMICOLON@52..53 ";"
1209 WHITESPACE@53..54 " "
1210 R_BRACE@54..55 "}"
1211 WHITESPACE@55..56 " "
1212 R_BRACE@56..57 "}"
1213 "#]]);
1214 }
1215
1216 #[test]
1217 fn parse_view_with_input() {
1218 check_file_no_errors("program test.aleo { view fn q(addr: address, k: u32) -> u64 { return 1u64; } }");
1219 }
1220
1221 #[test]
1222 fn parse_final_view_rejected() {
1223 let input = "program test.aleo { final view fn q() {} }";
1224 let (tokens, _) = lex(input);
1225 let mut parser = Parser::new(input, &tokens);
1226 let root = parser.start();
1227 parser.parse_file_items();
1228 root.complete(&mut parser, ROOT);
1229 let parse: Parse = parser.finish(vec![]);
1230 let errors = parse.errors();
1231 assert!(
1232 errors.iter().any(|e| e.message.contains("`final` and `view` cannot be combined")),
1233 "expected `final view` rejection, got: {errors:?}"
1234 );
1235 }
1236
1237 #[test]
1242 fn parse_function_const_generic_single() {
1243 check_file_no_errors("program test.aleo { fn foo::[N: u32]() {} }");
1244 }
1245
1246 #[test]
1247 fn parse_function_const_generic_multi() {
1248 check_file_no_errors("program test.aleo { fn bar::[N: u32, M: u32](arr: u32) -> u32 { return 0u32; } }");
1249 }
1250
1251 #[test]
1252 fn parse_function_const_generic_empty() {
1253 check_file_no_errors("program test.aleo { fn baz::[]() {} }");
1254 }
1255
1256 #[test]
1257 fn parse_final_entry_const_generic() {
1258 check_file_no_errors("program test.aleo { fn t::[N: u32]() -> Final { return final {}; } }");
1259 }
1260
1261 #[test]
1262 fn parse_struct_const_generic() {
1263 check_file_no_errors("program test.aleo { struct Foo::[N: u32] { arr: u32, } }");
1264 }
1265
1266 #[test]
1267 fn parse_struct_const_generic_multi() {
1268 check_file_no_errors("program test.aleo { struct Matrix::[M: u32, N: u32] { data: u32, } }");
1269 }
1270
1271 #[test]
1272 fn parse_record_const_generic() {
1273 check_file_no_errors("program test.aleo { record Bar::[N: u32] { owner: address, } }");
1275 }
1276
1277 #[test]
1278 fn parse_transition() {
1279 check_file("program test.aleo { fn main(public x: u32) { } }", expect![[r#"
1280 ROOT@0..48
1281 PROGRAM_DECL@0..48
1282 KW_PROGRAM@0..7 "program"
1283 WHITESPACE@7..8 " "
1284 IDENT@8..12 "test"
1285 DOT@12..13 "."
1286 KW_ALEO@13..17 "aleo"
1287 WHITESPACE@17..18 " "
1288 L_BRACE@18..19 "{"
1289 FUNCTION_DEF@19..46
1290 WHITESPACE@19..20 " "
1291 KW_FN@20..22 "fn"
1292 WHITESPACE@22..23 " "
1293 IDENT@23..27 "main"
1294 PARAM_LIST@27..42
1295 L_PAREN@27..28 "("
1296 PARAM_PUBLIC@28..41
1297 KW_PUBLIC@28..34 "public"
1298 WHITESPACE@34..35 " "
1299 IDENT@35..36 "x"
1300 COLON@36..37 ":"
1301 WHITESPACE@37..38 " "
1302 TYPE_PRIMITIVE@38..41
1303 KW_U32@38..41 "u32"
1304 R_PAREN@41..42 ")"
1305 WHITESPACE@42..43 " "
1306 BLOCK@43..46
1307 L_BRACE@43..44 "{"
1308 WHITESPACE@44..45 " "
1309 R_BRACE@45..46 "}"
1310 WHITESPACE@46..47 " "
1311 R_BRACE@47..48 "}"
1312 "#]]);
1313 }
1314
1315 #[test]
1320 fn parse_record_visibility() {
1321 check_file("program test.aleo { record Token { public owner: address, private amount: u64, } }", expect![[
1322 r#"
1323 ROOT@0..82
1324 PROGRAM_DECL@0..82
1325 KW_PROGRAM@0..7 "program"
1326 WHITESPACE@7..8 " "
1327 IDENT@8..12 "test"
1328 DOT@12..13 "."
1329 KW_ALEO@13..17 "aleo"
1330 WHITESPACE@17..18 " "
1331 L_BRACE@18..19 "{"
1332 RECORD_DEF@19..80
1333 WHITESPACE@19..20 " "
1334 KW_RECORD@20..26 "record"
1335 WHITESPACE@26..27 " "
1336 IDENT@27..32 "Token"
1337 WHITESPACE@32..33 " "
1338 L_BRACE@33..34 "{"
1339 WHITESPACE@34..35 " "
1340 STRUCT_MEMBER_PUBLIC@35..56
1341 KW_PUBLIC@35..41 "public"
1342 WHITESPACE@41..42 " "
1343 IDENT@42..47 "owner"
1344 COLON@47..48 ":"
1345 WHITESPACE@48..49 " "
1346 TYPE_PRIMITIVE@49..56
1347 KW_ADDRESS@49..56 "address"
1348 COMMA@56..57 ","
1349 WHITESPACE@57..58 " "
1350 STRUCT_MEMBER_PRIVATE@58..77
1351 KW_PRIVATE@58..65 "private"
1352 WHITESPACE@65..66 " "
1353 IDENT@66..72 "amount"
1354 COLON@72..73 ":"
1355 WHITESPACE@73..74 " "
1356 TYPE_PRIMITIVE@74..77
1357 KW_U64@74..77 "u64"
1358 COMMA@77..78 ","
1359 WHITESPACE@78..79 " "
1360 R_BRACE@79..80 "}"
1361 WHITESPACE@80..81 " "
1362 R_BRACE@81..82 "}"
1363 "#
1364 ]]);
1365 }
1366
1367 #[test]
1372 fn parse_final_fn_with_return() {
1373 check_file("program test.aleo { final fn main(public x: u32) -> Final { return final {}; } }", expect![[r#"
1374 ROOT@0..80
1375 PROGRAM_DECL@0..80
1376 KW_PROGRAM@0..7 "program"
1377 WHITESPACE@7..8 " "
1378 IDENT@8..12 "test"
1379 DOT@12..13 "."
1380 KW_ALEO@13..17 "aleo"
1381 WHITESPACE@17..18 " "
1382 L_BRACE@18..19 "{"
1383 FINAL_FN_DEF@19..78
1384 WHITESPACE@19..20 " "
1385 KW_FINAL@20..25 "final"
1386 WHITESPACE@25..26 " "
1387 KW_FN@26..28 "fn"
1388 WHITESPACE@28..29 " "
1389 IDENT@29..33 "main"
1390 PARAM_LIST@33..48
1391 L_PAREN@33..34 "("
1392 PARAM_PUBLIC@34..47
1393 KW_PUBLIC@34..40 "public"
1394 WHITESPACE@40..41 " "
1395 IDENT@41..42 "x"
1396 COLON@42..43 ":"
1397 WHITESPACE@43..44 " "
1398 TYPE_PRIMITIVE@44..47
1399 KW_U32@44..47 "u32"
1400 R_PAREN@47..48 ")"
1401 WHITESPACE@48..49 " "
1402 ARROW@49..51 "->"
1403 WHITESPACE@51..52 " "
1404 TYPE_FINAL@52..58
1405 KW_FINAL_UPPER@52..57 "Final"
1406 WHITESPACE@57..58 " "
1407 BLOCK@58..78
1408 L_BRACE@58..59 "{"
1409 WHITESPACE@59..60 " "
1410 RETURN_STMT@60..76
1411 KW_RETURN@60..66 "return"
1412 WHITESPACE@66..67 " "
1413 FINAL_EXPR@67..75
1414 KW_FINAL@67..72 "final"
1415 WHITESPACE@72..73 " "
1416 BLOCK@73..75
1417 L_BRACE@73..74 "{"
1418 R_BRACE@74..75 "}"
1419 SEMICOLON@75..76 ";"
1420 WHITESPACE@76..77 " "
1421 R_BRACE@77..78 "}"
1422 WHITESPACE@78..79 " "
1423 R_BRACE@79..80 "}"
1424 "#]]);
1425 }
1426
1427 #[test]
1432 fn parse_function_return_tuple() {
1433 check_file(
1434 "program test.aleo { fn foo() -> (public u32, private field) { return (1u32, 2field); } }",
1435 expect![[r#"
1436 ROOT@0..88
1437 PROGRAM_DECL@0..88
1438 KW_PROGRAM@0..7 "program"
1439 WHITESPACE@7..8 " "
1440 IDENT@8..12 "test"
1441 DOT@12..13 "."
1442 KW_ALEO@13..17 "aleo"
1443 WHITESPACE@17..18 " "
1444 L_BRACE@18..19 "{"
1445 FUNCTION_DEF@19..86
1446 WHITESPACE@19..20 " "
1447 KW_FN@20..22 "fn"
1448 WHITESPACE@22..23 " "
1449 IDENT@23..26 "foo"
1450 PARAM_LIST@26..28
1451 L_PAREN@26..27 "("
1452 R_PAREN@27..28 ")"
1453 WHITESPACE@28..29 " "
1454 ARROW@29..31 "->"
1455 WHITESPACE@31..32 " "
1456 RETURN_TYPE@32..59
1457 L_PAREN@32..33 "("
1458 KW_PUBLIC@33..39 "public"
1459 WHITESPACE@39..40 " "
1460 TYPE_PRIMITIVE@40..43
1461 KW_U32@40..43 "u32"
1462 COMMA@43..44 ","
1463 WHITESPACE@44..45 " "
1464 KW_PRIVATE@45..52 "private"
1465 WHITESPACE@52..53 " "
1466 TYPE_PRIMITIVE@53..58
1467 KW_FIELD@53..58 "field"
1468 R_PAREN@58..59 ")"
1469 BLOCK@59..86
1470 WHITESPACE@59..60 " "
1471 L_BRACE@60..61 "{"
1472 WHITESPACE@61..62 " "
1473 RETURN_STMT@62..84
1474 KW_RETURN@62..68 "return"
1475 WHITESPACE@68..69 " "
1476 TUPLE_EXPR@69..83
1477 L_PAREN@69..70 "("
1478 LITERAL_INT@70..74
1479 INTEGER@70..74 "1u32"
1480 COMMA@74..75 ","
1481 WHITESPACE@75..76 " "
1482 LITERAL_FIELD@76..82
1483 INTEGER@76..82 "2field"
1484 R_PAREN@82..83 ")"
1485 SEMICOLON@83..84 ";"
1486 WHITESPACE@84..85 " "
1487 R_BRACE@85..86 "}"
1488 WHITESPACE@86..87 " "
1489 R_BRACE@87..88 "}"
1490 "#]],
1491 );
1492 }
1493
1494 #[test]
1499 fn parse_function_multi_annotation() {
1500 check_file("program test.aleo { @test @foo(k = \"v\") fn bar() { } }", expect![[r#"
1501 ROOT@0..54
1502 PROGRAM_DECL@0..54
1503 KW_PROGRAM@0..7 "program"
1504 WHITESPACE@7..8 " "
1505 IDENT@8..12 "test"
1506 DOT@12..13 "."
1507 KW_ALEO@13..17 "aleo"
1508 WHITESPACE@17..18 " "
1509 L_BRACE@18..19 "{"
1510 FUNCTION_DEF@19..52
1511 ANNOTATION@19..26
1512 WHITESPACE@19..20 " "
1513 AT@20..21 "@"
1514 IDENT@21..25 "test"
1515 WHITESPACE@25..26 " "
1516 ANNOTATION@26..39
1517 AT@26..27 "@"
1518 IDENT@27..30 "foo"
1519 L_PAREN@30..31 "("
1520 ANNOTATION_PAIR@31..38
1521 IDENT@31..32 "k"
1522 WHITESPACE@32..33 " "
1523 EQ@33..34 "="
1524 WHITESPACE@34..35 " "
1525 STRING@35..38 "\"v\""
1526 R_PAREN@38..39 ")"
1527 WHITESPACE@39..40 " "
1528 KW_FN@40..42 "fn"
1529 WHITESPACE@42..43 " "
1530 IDENT@43..46 "bar"
1531 PARAM_LIST@46..48
1532 L_PAREN@46..47 "("
1533 R_PAREN@47..48 ")"
1534 WHITESPACE@48..49 " "
1535 BLOCK@49..52
1536 L_BRACE@49..50 "{"
1537 WHITESPACE@50..51 " "
1538 R_BRACE@51..52 "}"
1539 WHITESPACE@52..53 " "
1540 R_BRACE@53..54 "}"
1541 "#]]);
1542 }
1543
1544 #[test]
1549 fn parse_storage() {
1550 check_file("program test.aleo { storage state: u64; }", expect![[r#"
1551 ROOT@0..41
1552 PROGRAM_DECL@0..41
1553 KW_PROGRAM@0..7 "program"
1554 WHITESPACE@7..8 " "
1555 IDENT@8..12 "test"
1556 DOT@12..13 "."
1557 KW_ALEO@13..17 "aleo"
1558 WHITESPACE@17..18 " "
1559 L_BRACE@18..19 "{"
1560 STORAGE_DEF@19..39
1561 WHITESPACE@19..20 " "
1562 KW_STORAGE@20..27 "storage"
1563 WHITESPACE@27..28 " "
1564 IDENT@28..33 "state"
1565 COLON@33..34 ":"
1566 WHITESPACE@34..35 " "
1567 TYPE_PRIMITIVE@35..38
1568 KW_U64@35..38 "u64"
1569 SEMICOLON@38..39 ";"
1570 WHITESPACE@39..40 " "
1571 R_BRACE@40..41 "}"
1572 "#]]);
1573 }
1574
1575 #[test]
1580 fn parse_script_rejected() {
1581 check_file("program test.aleo { script main() { } }", expect![[r#"
1582 ROOT@0..39
1583 PROGRAM_DECL@0..39
1584 KW_PROGRAM@0..7 "program"
1585 WHITESPACE@7..8 " "
1586 IDENT@8..12 "test"
1587 DOT@12..13 "."
1588 KW_ALEO@13..17 "aleo"
1589 WHITESPACE@17..18 " "
1590 L_BRACE@18..19 "{"
1591 WHITESPACE@19..20 " "
1592 KW_SCRIPT@20..26 "script"
1593 ERROR@26..37
1594 WHITESPACE@26..27 " "
1595 IDENT@27..31 "main"
1596 L_PAREN@31..32 "("
1597 R_PAREN@32..33 ")"
1598 WHITESPACE@33..34 " "
1599 L_BRACE@34..35 "{"
1600 WHITESPACE@35..36 " "
1601 R_BRACE@36..37 "}"
1602 WHITESPACE@37..38 " "
1603 R_BRACE@38..39 "}"
1604 "#]]);
1605 }
1606
1607 #[test]
1612 fn parse_program_with_items() {
1613 check_file("program test.aleo { struct Foo { x: u32, } fn bar() -> u32 { return 1u32; } }", expect![[r#"
1614 ROOT@0..77
1615 PROGRAM_DECL@0..77
1616 KW_PROGRAM@0..7 "program"
1617 WHITESPACE@7..8 " "
1618 IDENT@8..12 "test"
1619 DOT@12..13 "."
1620 KW_ALEO@13..17 "aleo"
1621 WHITESPACE@17..18 " "
1622 L_BRACE@18..19 "{"
1623 STRUCT_DEF@19..42
1624 WHITESPACE@19..20 " "
1625 KW_STRUCT@20..26 "struct"
1626 WHITESPACE@26..27 " "
1627 IDENT@27..30 "Foo"
1628 WHITESPACE@30..31 " "
1629 L_BRACE@31..32 "{"
1630 WHITESPACE@32..33 " "
1631 STRUCT_MEMBER@33..39
1632 IDENT@33..34 "x"
1633 COLON@34..35 ":"
1634 WHITESPACE@35..36 " "
1635 TYPE_PRIMITIVE@36..39
1636 KW_U32@36..39 "u32"
1637 COMMA@39..40 ","
1638 WHITESPACE@40..41 " "
1639 R_BRACE@41..42 "}"
1640 FUNCTION_DEF@42..75
1641 WHITESPACE@42..43 " "
1642 KW_FN@43..45 "fn"
1643 WHITESPACE@45..46 " "
1644 IDENT@46..49 "bar"
1645 PARAM_LIST@49..51
1646 L_PAREN@49..50 "("
1647 R_PAREN@50..51 ")"
1648 WHITESPACE@51..52 " "
1649 ARROW@52..54 "->"
1650 WHITESPACE@54..55 " "
1651 TYPE_PRIMITIVE@55..58
1652 KW_U32@55..58 "u32"
1653 BLOCK@58..75
1654 WHITESPACE@58..59 " "
1655 L_BRACE@59..60 "{"
1656 WHITESPACE@60..61 " "
1657 RETURN_STMT@61..73
1658 KW_RETURN@61..67 "return"
1659 WHITESPACE@67..68 " "
1660 LITERAL_INT@68..72
1661 INTEGER@68..72 "1u32"
1662 SEMICOLON@72..73 ";"
1663 WHITESPACE@73..74 " "
1664 R_BRACE@74..75 "}"
1665 WHITESPACE@75..76 " "
1666 R_BRACE@76..77 "}"
1667 "#]]);
1668 }
1669
1670 #[test]
1675 fn parse_import_invalid_network() {
1676 check_file("import foo.bar;", expect![[r#"
1680 ROOT@0..15
1681 IMPORT@0..15
1682 KW_IMPORT@0..6 "import"
1683 WHITESPACE@6..7 " "
1684 IDENT@7..10 "foo"
1685 DOT@10..11 "."
1686 IDENT@11..14 "bar"
1687 SEMICOLON@14..15 ";"
1688 "#]]);
1689 }
1690
1691 #[test]
1696 fn parse_annotation_space_after_at() {
1697 let (tokens, _) = lex("program test.aleo { @ test fn foo() { } }");
1699 let mut parser = Parser::new("program test.aleo { @ test fn foo() { } }", &tokens);
1700 let root = parser.start();
1701 parser.parse_file_items();
1702 root.complete(&mut parser, ROOT);
1703 let parse: Parse = parser.finish(vec![]);
1704 assert!(!parse.errors().is_empty(), "expected error for space after @, got none");
1705 }
1706}