1use crate::{Parse, ParseResult, ParseToEnd, Parser, ParserConsumed};
2
3use sway_ast::keywords::{
4 AbiToken, ClassToken, ColonToken, ConfigurableToken, ConstToken, EnumToken, FnToken, ImplToken,
5 ModToken, MutToken, OpenAngleBracketToken, RefToken, SelfToken, SemicolonToken, StorageToken,
6 StructToken, TraitToken, TypeToken, UseToken, WhereToken,
7};
8use sway_ast::{
9 FnArg, FnArgs, FnSignature, ItemConst, ItemEnum, ItemFn, ItemKind, ItemStruct, ItemTrait,
10 ItemTypeAlias, ItemUse, Submodule, TraitType, TypeField,
11};
12use sway_error::parser_error::ParseErrorKind;
13use sway_types::ast::Delimiter;
14use sway_types::{Ident, Span, Spanned};
15
16mod item_abi;
17mod item_configurable;
18mod item_const;
19mod item_enum;
20mod item_fn;
21mod item_impl;
22mod item_storage;
23mod item_struct;
24mod item_trait;
25mod item_type_alias;
26mod item_use;
27
28impl Parse for ItemKind {
29 fn parse(parser: &mut Parser) -> ParseResult<ItemKind> {
30 let mut visibility = parser.take();
35
36 let kind = if let Some(mut item) = parser.guarded_parse::<ModToken, Submodule>()? {
37 item.visibility = visibility.take();
38 ItemKind::Submodule(item)
39 } else if let Some(mut item) = parser.guarded_parse::<UseToken, ItemUse>()? {
40 item.visibility = visibility.take();
41 ItemKind::Use(item)
42 } else if let Some(mut item) = parser.guarded_parse::<ClassToken, ItemStruct>()? {
43 item.visibility = visibility.take();
44 ItemKind::Struct(item)
45 } else if let Some(mut item) = parser.guarded_parse::<StructToken, ItemStruct>()? {
46 item.visibility = visibility.take();
47 ItemKind::Struct(item)
48 } else if let Some(mut item) = parser.guarded_parse::<EnumToken, ItemEnum>()? {
49 item.visibility = visibility.take();
50 ItemKind::Enum(item)
51 } else if let Some(mut item) = parser.guarded_parse::<FnToken, ItemFn>()? {
52 item.fn_signature.visibility = visibility.take();
53 ItemKind::Fn(item)
54 } else if let Some(mut item) = parser.guarded_parse::<TraitToken, ItemTrait>()? {
55 item.visibility = visibility.take();
56 ItemKind::Trait(item)
57 } else if let Some(item) = parser.guarded_parse::<ImplToken, _>()? {
58 ItemKind::Impl(item)
59 } else if let Some(item) = parser.guarded_parse::<AbiToken, _>()? {
60 ItemKind::Abi(item)
61 } else if let Some(mut item) = parser.guarded_parse::<ConstToken, ItemConst>()? {
62 item.pub_token = visibility.take();
63 parser.take::<SemicolonToken>().ok_or_else(|| {
64 parser.emit_error(ParseErrorKind::ExpectedPunct {
65 kinds: vec![sway_types::ast::PunctKind::Semicolon],
66 })
67 })?;
68 ItemKind::Const(item)
69 } else if let Some(item) = parser.guarded_parse::<StorageToken, _>()? {
70 ItemKind::Storage(item)
71 } else if let Some(item) = parser.guarded_parse::<ConfigurableToken, _>()? {
72 ItemKind::Configurable(item)
73 } else if let Some(mut item) = parser.guarded_parse::<TypeToken, ItemTypeAlias>()? {
74 item.visibility = visibility.take();
75 ItemKind::TypeAlias(item)
76 } else {
77 return Err(parser.emit_error(ParseErrorKind::ExpectedAnItem));
78 };
79
80 let _ = parser.ban_visibility_qualifier(&visibility);
82
83 Ok(kind)
84 }
85
86 fn error(
87 spans: Box<[sway_types::Span]>,
88 error: sway_error::handler::ErrorEmitted,
89 ) -> Option<Self>
90 where
91 Self: Sized,
92 {
93 Some(ItemKind::Error(spans, error))
94 }
95}
96
97impl Parse for TypeField {
98 fn parse(parser: &mut Parser) -> ParseResult<TypeField> {
99 let visibility = parser.take();
100 let name: Ident = parser.parse()?;
101 let name_span = name.span();
102
103 if parser.peek::<ColonToken>().is_some() {
105 let colon_token = parser.parse()?;
106 let ty = parser.parse()?;
107 return Ok(TypeField {
108 visibility,
109 name,
110 colon_token,
111 ty,
112 });
113 }
114
115 if let Some((_inner_parser, brace_span)) = parser.enter_delimited(Delimiter::Brace) {
119 let error_span = Span::join(name_span, &brace_span);
120 return Err(parser.emit_error_with_span(
121 ParseErrorKind::MissingColonInEnumTypeField {
122 variant_name: name,
123 tuple_contents: None, },
125 error_span,
126 ));
127 }
128
129 if let Some((inner_parser, paren_span)) = parser.enter_delimited(Delimiter::Parenthesis) {
131 let tuple_contents_span = inner_parser.full_span().clone();
132 let error_span = Span::join(name_span.clone(), &paren_span);
133 return Err(parser.emit_error_with_span(
134 ParseErrorKind::MissingColonInEnumTypeField {
135 variant_name: name,
136 tuple_contents: Some(tuple_contents_span),
137 },
138 error_span,
139 ));
140 }
141
142 if parser.is_empty() || parser.peek::<sway_ast::CommaToken>().is_some() {
144 return Err(parser.emit_error_with_span(
145 ParseErrorKind::MissingColonInEnumTypeField {
146 variant_name: name,
147 tuple_contents: Some(Span::dummy()), },
149 name_span,
150 ));
151 }
152
153 Err(parser.emit_error_with_span(
155 ParseErrorKind::MissingColonInEnumTypeField {
156 variant_name: name,
157 tuple_contents: None,
158 },
159 name_span,
160 ))
161 }
162}
163
164impl ParseToEnd for FnArgs {
165 fn parse_to_end<'a, 'e>(
166 mut parser: Parser<'a, '_>,
167 ) -> ParseResult<(FnArgs, ParserConsumed<'a>)> {
168 let mut ref_self: Option<RefToken> = None;
169 let mut mutable_self: Option<MutToken> = None;
170 if parser.peek::<(MutToken, SelfToken)>().is_some()
171 || parser.peek::<(RefToken, MutToken, SelfToken)>().is_some()
172 {
173 ref_self = parser.take();
174 mutable_self = parser.take();
175 }
176 match parser.take() {
177 Some(self_token) => {
178 match parser.take() {
179 Some(comma_token) => {
180 let (args, consumed) = parser.parse_to_end()?;
181 let fn_args = FnArgs::NonStatic {
182 self_token,
183 ref_self,
184 mutable_self,
185 args_opt: Some((comma_token, args)),
186 };
187 Ok((fn_args, consumed))
188 }
189 None => {
190 let fn_args = FnArgs::NonStatic {
191 self_token,
192 ref_self,
193 mutable_self,
194 args_opt: None,
195 };
196 match parser.check_empty() {
197 Some(consumed) => Ok((fn_args, consumed)),
198 None => Err(parser
199 .emit_error(ParseErrorKind::ExpectedCommaOrCloseParenInFnArgs)),
200 }
201 }
202 }
203 }
204 None => {
205 let (args, consumed) = parser.parse_to_end()?;
206 let fn_args = FnArgs::Static(args);
207 Ok((fn_args, consumed))
208 }
209 }
210 }
211}
212
213impl Parse for FnArg {
214 fn parse(parser: &mut Parser) -> ParseResult<FnArg> {
215 Ok(FnArg {
216 pattern: parser.parse()?,
217 colon_token: parser.parse()?,
218 ty: parser.parse()?,
219 })
220 }
221}
222
223impl Parse for FnSignature {
224 fn parse(parser: &mut Parser) -> ParseResult<FnSignature> {
225 Ok(FnSignature {
226 visibility: parser.take(),
227 fn_token: parser.parse()?,
228 name: parser.parse()?,
229 generics: parser.guarded_parse::<OpenAngleBracketToken, _>()?,
230 arguments: parser.parse()?,
231 return_type_opt: match parser.take() {
232 Some(right_arrow_token) => {
233 let ty = parser.parse()?;
234 Some((right_arrow_token, ty))
235 }
236 None => None,
237 },
238 where_clause_opt: parser.guarded_parse::<WhereToken, _>()?,
239 })
240 }
241}
242
243impl Parse for TraitType {
244 fn parse(parser: &mut Parser) -> ParseResult<TraitType> {
245 let type_token = parser.parse()?;
246 let name = parser.parse()?;
247 let eq_token_opt = parser.take();
248 let ty_opt = match &eq_token_opt {
249 Some(_eq) => Some(parser.parse()?),
250 None => None,
251 };
252 let semicolon_token = parser.peek().unwrap_or_default();
253 Ok(TraitType {
254 type_token,
255 name,
256 eq_token_opt,
257 ty_opt,
258 semicolon_token,
259 })
260 }
261}
262
263#[cfg(test)]
266mod tests {
267 use super::*;
268 use crate::test_utils::parse;
269 use sway_ast::{AttributeDecl, Item, ItemTraitItem, Statement};
270
271 type ParameterizedAttr<'a> = (&'a str, Option<Vec<&'a str>>);
273
274 fn attributes(attributes: &[AttributeDecl]) -> Vec<Vec<ParameterizedAttr>> {
275 attributes
276 .iter()
277 .map(|attr_decl| {
278 attr_decl
279 .attribute
280 .get()
281 .into_iter()
282 .map(|att| {
283 (
284 att.name.as_str(),
285 att.args.as_ref().map(|arg| {
286 arg.get().into_iter().map(|a| a.name.as_str()).collect()
287 }),
288 )
289 })
290 .collect()
291 })
292 .collect()
293 }
294
295 #[test]
296 fn parse_doc_comment() {
297 let item = parse::<Item>(
298 r#"
299 // I will be ignored.
300 //! This is a misplaced inner doc comment.
301 /// This is an outer doc comment.
302 //! This is a misplaced inner doc comment.
303 // I will be ignored.
304 /// This is an outer doc comment.
305 // I will be ignored.
306 fn f() -> bool {
307 false
308 }
309 "#,
310 );
311 assert!(matches!(item.value, ItemKind::Fn(_)));
312 assert_eq!(
313 attributes(&item.attributes),
314 vec![
315 [(
316 "doc-comment",
317 Some(vec![" This is a misplaced inner doc comment."])
318 )],
319 [("doc-comment", Some(vec![" This is an outer doc comment."]))],
320 [(
321 "doc-comment",
322 Some(vec![" This is a misplaced inner doc comment."])
323 )],
324 [("doc-comment", Some(vec![" This is an outer doc comment."]))],
325 ]
326 );
327 }
328
329 #[test]
330 fn parse_doc_comment_struct() {
331 let item = parse::<Item>(
332 r#"
333 // I will be ignored.
334 //! This is a misplaced inner doc comment.
335 /// This is an outer doc comment.
336 //! This is a misplaced inner doc comment.
337 // I will be ignored.
338 /// This is an outer doc comment.
339 // I will be ignored.
340 struct MyStruct {
341 // I will be ignored.
342 //! This is a misplaced inner doc comment.
343 /// This is an outer doc comment.
344 //! This is a misplaced inner doc comment.
345 // I will be ignored.
346 /// This is an outer doc comment.
347 // I will be ignored.
348 a: bool,
349 }
350 "#,
351 );
352
353 assert!(matches!(item.value, ItemKind::Struct(_)));
355 assert_eq!(
356 attributes(&item.attributes),
357 vec![
358 [(
359 "doc-comment",
360 Some(vec![" This is a misplaced inner doc comment."])
361 )],
362 [("doc-comment", Some(vec![" This is an outer doc comment."]))],
363 [(
364 "doc-comment",
365 Some(vec![" This is a misplaced inner doc comment."])
366 )],
367 [("doc-comment", Some(vec![" This is an outer doc comment."]))],
368 ]
369 );
370
371 let item = match item.value {
373 ItemKind::Struct(item) => item.fields.inner.into_iter().next().unwrap(),
374 _ => unreachable!(),
375 };
376
377 assert_eq!(
378 attributes(&item.attributes),
379 vec![
380 [(
381 "doc-comment",
382 Some(vec![" This is a misplaced inner doc comment."])
383 )],
384 [("doc-comment", Some(vec![" This is an outer doc comment."]))],
385 [(
386 "doc-comment",
387 Some(vec![" This is a misplaced inner doc comment."])
388 )],
389 [("doc-comment", Some(vec![" This is an outer doc comment."]))],
390 ]
391 );
392 }
393
394 #[test]
395 fn parse_attributes_none() {
396 let item = parse::<Item>(
397 r#"
398 fn f() -> bool {
399 false
400 }
401 "#,
402 );
403
404 assert!(matches!(item.value, ItemKind::Fn(_)));
405 assert!(item.attributes.is_empty());
406 }
407
408 #[test]
409 fn parse_attributes_fn_basic() {
410 let item = parse::<Item>(
411 r#"
412 #[foo]
413 fn f() -> bool {
414 false
415 }
416 "#,
417 );
418
419 assert!(matches!(item.value, ItemKind::Fn(_)));
420 assert_eq!(attributes(&item.attributes), vec![[("foo", None)]]);
421 }
422
423 #[test]
424 fn parse_attributes_fn_one_arg_value() {
425 let item = parse::<Item>(
426 r#"
427 #[cfg(target = "evm")]
428 fn f() -> bool {
429 false
430 }
431 "#,
432 );
433
434 assert!(matches!(item.value, ItemKind::Fn(_)));
435 assert_eq!(
436 attributes(&item.attributes),
437 vec![[("cfg", Some(vec!["target"]))]]
438 );
439 }
440
441 #[test]
442 fn parse_attributes_fn_two_arg_values() {
443 let item = parse::<Item>(
444 r#"
445 #[cfg(target = "evm", feature = "test")]
446 fn f() -> bool {
447 false
448 }
449 "#,
450 );
451
452 assert!(matches!(item.value, ItemKind::Fn(_)));
453 assert_eq!(
454 attributes(&item.attributes),
455 vec![[("cfg", Some(vec!["target", "feature"]))]]
456 );
457 }
458
459 #[test]
460 fn parse_attributes_fn_two_basic() {
461 let item = parse::<Item>(
462 r#"
463 #[foo]
464 #[bar]
465 fn f() -> bool {
466 false
467 }
468 "#,
469 );
470
471 assert!(matches!(item.value, ItemKind::Fn(_)));
472
473 assert_eq!(
474 attributes(&item.attributes),
475 vec![[("foo", None)], [("bar", None)]]
476 );
477 }
478
479 #[test]
480 fn parse_attributes_fn_one_arg() {
481 let item = parse::<Item>(
482 r#"
483 #[foo(one)]
484 fn f() -> bool {
485 false
486 }
487 "#,
488 );
489
490 assert!(matches!(item.value, ItemKind::Fn(_)));
491 assert_eq!(
492 attributes(&item.attributes),
493 vec![[("foo", Some(vec!["one"]))]]
494 );
495 }
496
497 #[test]
498 fn parse_attributes_fn_empty_parens() {
499 let item = parse::<Item>(
500 r#"
501 #[foo()]
502 fn f() -> bool {
503 false
504 }
505 "#,
506 );
507
508 assert!(matches!(item.value, ItemKind::Fn(_)));
509 assert_eq!(attributes(&item.attributes), vec![[("foo", Some(vec![]))]]);
510 }
511
512 #[test]
513 fn parse_attributes_fn_zero_and_one_arg() {
514 let item = parse::<Item>(
515 r#"
516 #[bar]
517 #[foo(one)]
518 fn f() -> bool {
519 false
520 }
521 "#,
522 );
523
524 assert!(matches!(item.value, ItemKind::Fn(_)));
525 assert_eq!(
526 attributes(&item.attributes),
527 vec![[("bar", None)], [("foo", Some(vec!["one"]))]]
528 );
529 }
530
531 #[test]
532 fn parse_attributes_fn_one_and_zero_arg() {
533 let item = parse::<Item>(
534 r#"
535 #[foo(one)]
536 #[bar]
537 fn f() -> bool {
538 false
539 }
540 "#,
541 );
542
543 assert!(matches!(item.value, ItemKind::Fn(_)));
544 assert_eq!(
545 attributes(&item.attributes),
546 vec![[("foo", Some(vec!["one"]))], [("bar", None)]]
547 );
548 }
549
550 #[test]
551 fn parse_attributes_fn_two_args() {
552 let item = parse::<Item>(
553 r#"
554 #[foo(one, two)]
555 fn f() -> bool {
556 false
557 }
558 "#,
559 );
560
561 assert!(matches!(item.value, ItemKind::Fn(_)));
562 assert_eq!(
563 attributes(&item.attributes),
564 vec![[("foo", Some(vec!["one", "two"]))]]
565 );
566 }
567
568 #[test]
569 fn parse_attributes_fn_zero_one_and_three_args() {
570 let item = parse::<Item>(
571 r#"
572 #[bar]
573 #[foo(one)]
574 #[baz(two,three,four)]
575 fn f() -> bool {
576 false
577 }
578 "#,
579 );
580
581 assert!(matches!(item.value, ItemKind::Fn(_)));
582 assert_eq!(
583 attributes(&item.attributes),
584 vec![
585 [("bar", None)],
586 [("foo", Some(vec!["one"]))],
587 [("baz", Some(vec!["two", "three", "four"]))]
588 ]
589 );
590 }
591
592 #[test]
593 fn parse_attributes_fn_zero_one_and_three_args_in_one_attribute_decl() {
594 let item = parse::<Item>(
595 r#"
596 #[bar, foo(one), baz(two,three,four)]
597 fn f() -> bool {
598 false
599 }
600 "#,
601 );
602
603 assert!(matches!(item.value, ItemKind::Fn(_)));
604 assert_eq!(
605 attributes(&item.attributes),
606 vec![[
607 ("bar", None),
608 ("foo", Some(vec!["one"])),
609 ("baz", Some(vec!["two", "three", "four"]))
610 ]]
611 );
612 }
613
614 #[test]
615 fn parse_attributes_trait() {
616 let item = parse::<Item>(
617 r#"
618 trait T {
619 #[foo(one)]
620 #[bar]
621 fn f() -> bool;
622 } {
623 #[bar(one, two, three)]
624 fn g() -> bool {
625 f()
626 }
627 }
628 "#,
629 );
630
631 assert!(matches!(item.value, ItemKind::Trait(_)));
633 assert_eq!(item.attributes.len(), 0);
634
635 if let ItemKind::Trait(item_trait) = item.value {
636 let mut decls = item_trait.trait_items.get().iter();
637
638 let trait_item = decls.next();
639 assert!(trait_item.is_some());
640 let annotated = trait_item.unwrap();
641 if let ItemTraitItem::Fn(_fn_sig, _) = &annotated.value {
642 assert_eq!(
643 attributes(&annotated.attributes),
644 vec![[("foo", Some(vec!["one"]))], [("bar", None)]]
645 );
646 }
647
648 assert!(decls.next().is_none());
649
650 assert!(item_trait.trait_defs_opt.is_some());
651 let mut defs = item_trait.trait_defs_opt.as_ref().unwrap().get().iter();
652
653 let g_sig = defs.next();
654 assert!(g_sig.is_some());
655
656 assert_eq!(
657 attributes(&g_sig.unwrap().attributes),
658 vec![[("bar", Some(vec!["one", "two", "three"]))],]
659 );
660
661 assert!(defs.next().is_none());
662 } else {
663 panic!("Parsed trait is not a trait.");
664 }
665 }
666
667 #[test]
668 fn parse_attributes_abi() {
669 let item = parse::<Item>(
670 r#"
671 abi A {
672 #[bar(one, two, three)]
673 fn f() -> bool;
674
675 #[foo]
676 fn g() -> u64;
677 } {
678 #[baz(one)]
679 fn h() -> bool {
680 f()
681 }
682 }
683 "#,
684 );
685
686 assert!(matches!(item.value, ItemKind::Abi(_)));
688 assert_eq!(item.attributes.len(), 0);
689
690 if let ItemKind::Abi(item_abi) = item.value {
691 let mut decls = item_abi.abi_items.get().iter();
692
693 let f_sig = decls.next();
694 assert!(f_sig.is_some());
695
696 assert_eq!(
697 attributes(&f_sig.unwrap().attributes),
698 vec![[("bar", Some(vec!["one", "two", "three"]))],]
699 );
700
701 let g_sig = decls.next();
702 assert!(g_sig.is_some());
703
704 assert_eq!(
705 attributes(&g_sig.unwrap().attributes),
706 vec![[("foo", None)],]
707 );
708 assert!(decls.next().is_none());
709
710 assert!(item_abi.abi_defs_opt.is_some());
711 let mut defs = item_abi.abi_defs_opt.as_ref().unwrap().get().iter();
712
713 let h_sig = defs.next();
714 assert!(h_sig.is_some());
715
716 assert_eq!(
717 attributes(&h_sig.unwrap().attributes),
718 vec![[("baz", Some(vec!["one"]))],]
719 );
720 assert!(defs.next().is_none());
721 } else {
722 panic!("Parsed ABI is not an ABI.");
723 }
724 }
725
726 #[test]
727 fn parse_attributes_doc_comment() {
728 let item = parse::<Item>(
729 r#"
730 /// This is a doc comment.
731 /// This is another doc comment.
732 fn f() -> bool {
733 false
734 }
735 "#,
736 );
737
738 assert!(matches!(item.value, ItemKind::Fn(_)));
739 assert_eq!(
740 attributes(&item.attributes),
741 vec![
742 [("doc-comment", Some(vec![" This is a doc comment."]))],
743 [("doc-comment", Some(vec![" This is another doc comment."]))]
744 ]
745 );
746 }
747
748 #[test]
749 fn parse_nested_annotations() {
750 let item = parse::<ItemFn>(
751 r#"
752 fn fun() {
753 /// Struct Comment.
754 #[allow(dead_code)]
755 struct S {
756 /// Field Comment.
757 #[allow(dead_code)]
758 field: u8,
759 }
760
761 /// Const Comment.
762 #[allow(dead_code)]
763 const CONST: u8 = 0;
764 }
765 "#,
766 );
767 let item_attributes =
768 item.body
769 .inner
770 .statements
771 .iter()
772 .fold(vec![], |mut acc, statement| match statement {
773 Statement::Item(item) => {
774 acc.push(attributes(&item.attributes));
775 if let ItemKind::Struct(item_struct) = &item.value {
776 let mut struct_attributes = item_struct
777 .fields
778 .inner
779 .value_separator_pairs
780 .iter()
781 .map(|(field, _)| attributes(&field.attributes))
782 .collect::<Vec<_>>();
783 acc.append(&mut struct_attributes);
784 }
785 acc
786 }
787 _ => acc,
788 });
789 assert_eq!(
790 item_attributes,
791 vec![
792 vec![
793 [("doc-comment", Some(vec![" Struct Comment."]))],
794 [("allow", Some(vec!["dead_code"]))],
795 ],
796 vec![
797 [("doc-comment", Some(vec![" Field Comment."]))],
798 [("allow", Some(vec!["dead_code"]))],
799 ],
800 vec![
801 [("doc-comment", Some(vec![" Const Comment."]))],
802 [("allow", Some(vec!["dead_code"]))],
803 ]
804 ],
805 );
806 }
807}