sway_parse/item/
mod.rs

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;
13
14mod item_abi;
15mod item_configurable;
16mod item_const;
17mod item_enum;
18mod item_fn;
19mod item_impl;
20mod item_storage;
21mod item_struct;
22mod item_trait;
23mod item_type_alias;
24mod item_use;
25
26impl Parse for ItemKind {
27    fn parse(parser: &mut Parser) -> ParseResult<ItemKind> {
28        // FIXME(Centril): Visibility should be moved out of `ItemKind` variants,
29        // introducing a struct `Item` that holds the visibility and the kind,
30        // and then validate in an "AST validation" step which kinds that should have `pub`s.
31
32        let mut visibility = parser.take();
33
34        let kind = if let Some(mut item) = parser.guarded_parse::<ModToken, Submodule>()? {
35            item.visibility = visibility.take();
36            ItemKind::Submodule(item)
37        } else if let Some(mut item) = parser.guarded_parse::<UseToken, ItemUse>()? {
38            item.visibility = visibility.take();
39            ItemKind::Use(item)
40        } else if let Some(mut item) = parser.guarded_parse::<ClassToken, ItemStruct>()? {
41            item.visibility = visibility.take();
42            ItemKind::Struct(item)
43        } else if let Some(mut item) = parser.guarded_parse::<StructToken, ItemStruct>()? {
44            item.visibility = visibility.take();
45            ItemKind::Struct(item)
46        } else if let Some(mut item) = parser.guarded_parse::<EnumToken, ItemEnum>()? {
47            item.visibility = visibility.take();
48            ItemKind::Enum(item)
49        } else if let Some(mut item) = parser.guarded_parse::<FnToken, ItemFn>()? {
50            item.fn_signature.visibility = visibility.take();
51            ItemKind::Fn(item)
52        } else if let Some(mut item) = parser.guarded_parse::<TraitToken, ItemTrait>()? {
53            item.visibility = visibility.take();
54            ItemKind::Trait(item)
55        } else if let Some(item) = parser.guarded_parse::<ImplToken, _>()? {
56            ItemKind::Impl(item)
57        } else if let Some(item) = parser.guarded_parse::<AbiToken, _>()? {
58            ItemKind::Abi(item)
59        } else if let Some(mut item) = parser.guarded_parse::<ConstToken, ItemConst>()? {
60            item.visibility = visibility.take();
61            parser.take::<SemicolonToken>().ok_or_else(|| {
62                parser.emit_error(ParseErrorKind::ExpectedPunct {
63                    kinds: vec![sway_types::ast::PunctKind::Semicolon],
64                })
65            })?;
66            ItemKind::Const(item)
67        } else if let Some(item) = parser.guarded_parse::<StorageToken, _>()? {
68            ItemKind::Storage(item)
69        } else if let Some(item) = parser.guarded_parse::<ConfigurableToken, _>()? {
70            ItemKind::Configurable(item)
71        } else if let Some(mut item) = parser.guarded_parse::<TypeToken, ItemTypeAlias>()? {
72            item.visibility = visibility.take();
73            ItemKind::TypeAlias(item)
74        } else {
75            return Err(parser.emit_error(ParseErrorKind::ExpectedAnItem));
76        };
77
78        // Ban visibility qualifiers that haven't been consumed, but do so with recovery.
79        let _ = parser.ban_visibility_qualifier(&visibility);
80
81        Ok(kind)
82    }
83
84    fn error(
85        spans: Box<[sway_types::Span]>,
86        error: sway_error::handler::ErrorEmitted,
87    ) -> Option<Self>
88    where
89        Self: Sized,
90    {
91        Some(ItemKind::Error(spans, error))
92    }
93}
94
95impl Parse for TypeField {
96    fn parse(parser: &mut Parser) -> ParseResult<TypeField> {
97        let visibility = parser.take();
98        Ok(TypeField {
99            visibility,
100            name: parser.parse()?,
101            colon_token: if parser.peek::<ColonToken>().is_some() {
102                parser.parse()
103            } else {
104                Err(parser.emit_error(ParseErrorKind::MissingColonInEnumTypeField))
105            }?,
106            ty: parser.parse()?,
107        })
108    }
109}
110
111impl ParseToEnd for FnArgs {
112    fn parse_to_end<'a, 'e>(
113        mut parser: Parser<'a, '_>,
114    ) -> ParseResult<(FnArgs, ParserConsumed<'a>)> {
115        let mut ref_self: Option<RefToken> = None;
116        let mut mutable_self: Option<MutToken> = None;
117        if parser.peek::<(MutToken, SelfToken)>().is_some()
118            || parser.peek::<(RefToken, MutToken, SelfToken)>().is_some()
119        {
120            ref_self = parser.take();
121            mutable_self = parser.take();
122        }
123        match parser.take() {
124            Some(self_token) => {
125                match parser.take() {
126                    Some(comma_token) => {
127                        let (args, consumed) = parser.parse_to_end()?;
128                        let fn_args = FnArgs::NonStatic {
129                            self_token,
130                            ref_self,
131                            mutable_self,
132                            args_opt: Some((comma_token, args)),
133                        };
134                        Ok((fn_args, consumed))
135                    }
136                    None => {
137                        let fn_args = FnArgs::NonStatic {
138                            self_token,
139                            ref_self,
140                            mutable_self,
141                            args_opt: None,
142                        };
143                        match parser.check_empty() {
144                            Some(consumed) => Ok((fn_args, consumed)),
145                            None => Err(parser
146                                .emit_error(ParseErrorKind::ExpectedCommaOrCloseParenInFnArgs)),
147                        }
148                    }
149                }
150            }
151            None => {
152                let (args, consumed) = parser.parse_to_end()?;
153                let fn_args = FnArgs::Static(args);
154                Ok((fn_args, consumed))
155            }
156        }
157    }
158}
159
160impl Parse for FnArg {
161    fn parse(parser: &mut Parser) -> ParseResult<FnArg> {
162        Ok(FnArg {
163            pattern: parser.parse()?,
164            colon_token: parser.parse()?,
165            ty: parser.parse()?,
166        })
167    }
168}
169
170impl Parse for FnSignature {
171    fn parse(parser: &mut Parser) -> ParseResult<FnSignature> {
172        Ok(FnSignature {
173            visibility: parser.take(),
174            fn_token: parser.parse()?,
175            name: parser.parse()?,
176            generics: parser.guarded_parse::<OpenAngleBracketToken, _>()?,
177            arguments: parser.parse()?,
178            return_type_opt: match parser.take() {
179                Some(right_arrow_token) => {
180                    let ty = parser.parse()?;
181                    Some((right_arrow_token, ty))
182                }
183                None => None,
184            },
185            where_clause_opt: parser.guarded_parse::<WhereToken, _>()?,
186        })
187    }
188}
189
190impl Parse for TraitType {
191    fn parse(parser: &mut Parser) -> ParseResult<TraitType> {
192        let type_token = parser.parse()?;
193        let name = parser.parse()?;
194        let eq_token_opt = parser.take();
195        let ty_opt = match &eq_token_opt {
196            Some(_eq) => Some(parser.parse()?),
197            None => None,
198        };
199        let semicolon_token = parser.peek().unwrap_or_default();
200        Ok(TraitType {
201            type_token,
202            name,
203            eq_token_opt,
204            ty_opt,
205            semicolon_token,
206        })
207    }
208}
209
210// -------------------------------------------------------------------------------------------------
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215    use crate::test_utils::parse;
216    use sway_ast::{AttributeDecl, Item, ItemTraitItem};
217
218    // Attribute name and its list of parameters
219    type ParameterizedAttr<'a> = (&'a str, Option<Vec<&'a str>>);
220
221    fn attributes(attribute_list: &[AttributeDecl]) -> Vec<Vec<ParameterizedAttr>> {
222        attribute_list
223            .iter()
224            .map(|attr_decl| {
225                attr_decl
226                    .attribute
227                    .get()
228                    .into_iter()
229                    .map(|att| {
230                        (
231                            att.name.as_str(),
232                            att.args.as_ref().map(|arg| {
233                                arg.get().into_iter().map(|a| a.name.as_str()).collect()
234                            }),
235                        )
236                    })
237                    .collect()
238            })
239            .collect()
240    }
241
242    #[test]
243    fn parse_doc_comment() {
244        let item = parse::<Item>(
245            r#"
246            // I will be ignored.
247            //! I will be ignored.
248            /// This is a doc comment.
249            //! I will be ignored.
250            // I will be ignored.
251            fn f() -> bool {
252                false
253            }
254            "#,
255        );
256        assert!(matches!(item.value, ItemKind::Fn(_)));
257        assert_eq!(
258            attributes(&item.attribute_list),
259            vec![[("doc-comment", Some(vec![" This is a doc comment."]))]]
260        );
261    }
262
263    #[test]
264    fn parse_doc_comment_struct() {
265        let item = parse::<Item>(
266            r#"
267            // I will be ignored.
268            //! I will be ignored. 
269            /// This is a doc comment.
270            //! I will be ignored.
271            // I will be ignored.
272            struct MyStruct {
273                // I will be ignored.
274                //! I will be ignored.
275                /// This is a doc comment.
276                //! I will be ignored.
277                // I will be ignored.
278                a: bool,
279            }
280            "#,
281        );
282
283        /* struct annotations */
284        assert!(matches!(item.value, ItemKind::Struct(_)));
285        assert_eq!(
286            attributes(&item.attribute_list),
287            vec![[("doc-comment", Some(vec![" This is a doc comment."]))]]
288        );
289
290        /* struct field annotations */
291        let item = match item.value {
292            ItemKind::Struct(item) => item.fields.inner.into_iter().next().unwrap(),
293            _ => unreachable!(),
294        };
295
296        assert_eq!(
297            attributes(&item.attribute_list),
298            vec![[("doc-comment", Some(vec![" This is a doc comment."]))]]
299        );
300    }
301
302    #[test]
303    fn parse_attributes_none() {
304        let item = parse::<Item>(
305            r#"
306            fn f() -> bool {
307                false
308            }
309            "#,
310        );
311
312        assert!(matches!(item.value, ItemKind::Fn(_)));
313        assert!(item.attribute_list.is_empty());
314    }
315
316    #[test]
317    fn parse_attributes_fn_basic() {
318        let item = parse::<Item>(
319            r#"
320            #[foo]
321            fn f() -> bool {
322                false
323            }
324            "#,
325        );
326
327        assert!(matches!(item.value, ItemKind::Fn(_)));
328        assert_eq!(attributes(&item.attribute_list), vec![[("foo", None)]]);
329    }
330
331    #[test]
332    fn parse_attributes_fn_one_arg_value() {
333        let item = parse::<Item>(
334            r#"
335            #[cfg(target = "evm")]
336            fn f() -> bool {
337                false
338            }
339            "#,
340        );
341
342        assert!(matches!(item.value, ItemKind::Fn(_)));
343        assert_eq!(
344            attributes(&item.attribute_list),
345            vec![[("cfg", Some(vec!["target"]))]]
346        );
347    }
348
349    #[test]
350    fn parse_attributes_fn_two_arg_values() {
351        let item = parse::<Item>(
352            r#"
353            #[cfg(target = "evm", feature = "test")]
354            fn f() -> bool {
355                false
356            }
357            "#,
358        );
359
360        assert!(matches!(item.value, ItemKind::Fn(_)));
361        assert_eq!(
362            attributes(&item.attribute_list),
363            vec![[("cfg", Some(vec!["target", "feature"]))]]
364        );
365    }
366
367    #[test]
368    fn parse_attributes_fn_two_basic() {
369        let item = parse::<Item>(
370            r#"
371            #[foo]
372            #[bar]
373            fn f() -> bool {
374                false
375            }
376            "#,
377        );
378
379        assert!(matches!(item.value, ItemKind::Fn(_)));
380
381        assert_eq!(
382            attributes(&item.attribute_list),
383            vec![[("foo", None)], [("bar", None)]]
384        );
385    }
386
387    #[test]
388    fn parse_attributes_fn_one_arg() {
389        let item = parse::<Item>(
390            r#"
391            #[foo(one)]
392            fn f() -> bool {
393                false
394            }
395            "#,
396        );
397
398        assert!(matches!(item.value, ItemKind::Fn(_)));
399        assert_eq!(
400            attributes(&item.attribute_list),
401            vec![[("foo", Some(vec!["one"]))]]
402        );
403    }
404
405    #[test]
406    fn parse_attributes_fn_empty_parens() {
407        let item = parse::<Item>(
408            r#"
409            #[foo()]
410            fn f() -> bool {
411                false
412            }
413            "#,
414        );
415
416        assert!(matches!(item.value, ItemKind::Fn(_)));
417        assert_eq!(
418            attributes(&item.attribute_list),
419            vec![[("foo", Some(vec![]))]]
420        );
421    }
422
423    #[test]
424    fn parse_attributes_fn_zero_and_one_arg() {
425        let item = parse::<Item>(
426            r#"
427            #[bar]
428            #[foo(one)]
429            fn f() -> bool {
430                false
431            }
432            "#,
433        );
434
435        assert!(matches!(item.value, ItemKind::Fn(_)));
436        assert_eq!(
437            attributes(&item.attribute_list),
438            vec![[("bar", None)], [("foo", Some(vec!["one"]))]]
439        );
440    }
441
442    #[test]
443    fn parse_attributes_fn_one_and_zero_arg() {
444        let item = parse::<Item>(
445            r#"
446            #[foo(one)]
447            #[bar]
448            fn f() -> bool {
449                false
450            }
451            "#,
452        );
453
454        assert!(matches!(item.value, ItemKind::Fn(_)));
455        assert_eq!(
456            attributes(&item.attribute_list),
457            vec![[("foo", Some(vec!["one"]))], [("bar", None)]]
458        );
459    }
460
461    #[test]
462    fn parse_attributes_fn_two_args() {
463        let item = parse::<Item>(
464            r#"
465            #[foo(one, two)]
466            fn f() -> bool {
467                false
468            }
469            "#,
470        );
471
472        assert!(matches!(item.value, ItemKind::Fn(_)));
473        assert_eq!(
474            attributes(&item.attribute_list),
475            vec![[("foo", Some(vec!["one", "two"]))]]
476        );
477    }
478
479    #[test]
480    fn parse_attributes_fn_zero_one_and_three_args() {
481        let item = parse::<Item>(
482            r#"
483            #[bar]
484            #[foo(one)]
485            #[baz(two,three,four)]
486            fn f() -> bool {
487                false
488            }
489            "#,
490        );
491
492        assert!(matches!(item.value, ItemKind::Fn(_)));
493        assert_eq!(
494            attributes(&item.attribute_list),
495            vec![
496                [("bar", None)],
497                [("foo", Some(vec!["one"]))],
498                [("baz", Some(vec!["two", "three", "four"]))]
499            ]
500        );
501    }
502
503    #[test]
504    fn parse_attributes_fn_zero_one_and_three_args_in_one_attribute_decl() {
505        let item = parse::<Item>(
506            r#"
507            #[bar, foo(one), baz(two,three,four)]
508            fn f() -> bool {
509                false
510            }
511            "#,
512        );
513
514        assert!(matches!(item.value, ItemKind::Fn(_)));
515        assert_eq!(
516            attributes(&item.attribute_list),
517            vec![[
518                ("bar", None),
519                ("foo", Some(vec!["one"])),
520                ("baz", Some(vec!["two", "three", "four"]))
521            ]]
522        );
523    }
524
525    #[test]
526    fn parse_attributes_trait() {
527        let item = parse::<Item>(
528            r#"
529            trait T {
530                #[foo(one)]
531                #[bar]
532                fn f() -> bool;
533            } {
534                #[bar(one, two, three)]
535                fn g() -> bool {
536                    f()
537                }
538            }
539            "#,
540        );
541
542        // The trait itself has no attributes.
543        assert!(matches!(item.value, ItemKind::Trait(_)));
544        assert_eq!(item.attribute_list.len(), 0);
545
546        if let ItemKind::Trait(item_trait) = item.value {
547            let mut decls = item_trait.trait_items.get().iter();
548
549            let trait_item = decls.next();
550            assert!(trait_item.is_some());
551            let annotated = trait_item.unwrap();
552            if let ItemTraitItem::Fn(_fn_sig, _) = &annotated.value {
553                assert_eq!(
554                    attributes(&annotated.attribute_list),
555                    vec![[("foo", Some(vec!["one"]))], [("bar", None)]]
556                );
557            }
558
559            assert!(decls.next().is_none());
560
561            assert!(item_trait.trait_defs_opt.is_some());
562            let mut defs = item_trait.trait_defs_opt.as_ref().unwrap().get().iter();
563
564            let g_sig = defs.next();
565            assert!(g_sig.is_some());
566
567            assert_eq!(
568                attributes(&g_sig.unwrap().attribute_list),
569                vec![[("bar", Some(vec!["one", "two", "three"]))],]
570            );
571
572            assert!(defs.next().is_none());
573        } else {
574            panic!("Parsed trait is not a trait.");
575        }
576    }
577
578    #[test]
579    fn parse_attributes_abi() {
580        let item = parse::<Item>(
581            r#"
582            abi A {
583                #[bar(one, two, three)]
584                fn f() -> bool;
585
586                #[foo]
587                fn g() -> u64;
588            } {
589                #[baz(one)]
590                fn h() -> bool {
591                    f()
592                }
593            }
594            "#,
595        );
596
597        // The ABI itself has no attributes.
598        assert!(matches!(item.value, ItemKind::Abi(_)));
599        assert_eq!(item.attribute_list.len(), 0);
600
601        if let ItemKind::Abi(item_abi) = item.value {
602            let mut decls = item_abi.abi_items.get().iter();
603
604            let f_sig = decls.next();
605            assert!(f_sig.is_some());
606
607            assert_eq!(
608                attributes(&f_sig.unwrap().attribute_list),
609                vec![[("bar", Some(vec!["one", "two", "three"]))],]
610            );
611
612            let g_sig = decls.next();
613            assert!(g_sig.is_some());
614
615            assert_eq!(
616                attributes(&g_sig.unwrap().attribute_list),
617                vec![[("foo", None)],]
618            );
619            assert!(decls.next().is_none());
620
621            assert!(item_abi.abi_defs_opt.is_some());
622            let mut defs = item_abi.abi_defs_opt.as_ref().unwrap().get().iter();
623
624            let h_sig = defs.next();
625            assert!(h_sig.is_some());
626
627            assert_eq!(
628                attributes(&h_sig.unwrap().attribute_list),
629                vec![[("baz", Some(vec!["one"]))],]
630            );
631            assert!(defs.next().is_none());
632        } else {
633            panic!("Parsed ABI is not an ABI.");
634        }
635    }
636
637    #[test]
638    fn parse_attributes_doc_comment() {
639        let item = parse::<Item>(
640            r#"
641            /// This is a doc comment.
642            /// This is another doc comment.
643            fn f() -> bool {
644                false
645            }
646            "#,
647        );
648
649        assert!(matches!(item.value, ItemKind::Fn(_)));
650        assert_eq!(
651            attributes(&item.attribute_list),
652            vec![
653                [("doc-comment", Some(vec![" This is a doc comment."]))],
654                [("doc-comment", Some(vec![" This is another doc comment."]))]
655            ]
656        );
657    }
658}