sway_parse/
module.rs

1use crate::{Parse, ParseResult, ParseToEnd, Parser, ParserConsumed};
2
3use sway_ast::{
4    attribute::{Annotated, Attribute, AttributeArg, AttributeHashKind},
5    brackets::SquareBrackets,
6    keywords::{HashBangToken, Token},
7    token::{DocComment, DocStyle},
8    AttributeDecl, Module, ModuleKind, Parens, Punctuated,
9};
10use sway_error::parser_error::ParseErrorKind;
11use sway_types::{constants::DOC_COMMENT_ATTRIBUTE_NAME, Ident};
12
13impl Parse for ModuleKind {
14    fn parse(parser: &mut Parser) -> ParseResult<Self> {
15        if let Some(script_token) = parser.take() {
16            Ok(Self::Script { script_token })
17        } else if let Some(contract_token) = parser.take() {
18            Ok(Self::Contract { contract_token })
19        } else if let Some(predicate_token) = parser.take() {
20            Ok(Self::Predicate { predicate_token })
21        } else if let Some(library_token) = parser.take() {
22            Ok(Self::Library { library_token })
23        } else {
24            Err(parser.emit_error(ParseErrorKind::ExpectedModuleKind))
25        }
26    }
27}
28
29impl ParseToEnd for Annotated<Module> {
30    fn parse_to_end<'a, 'e>(mut parser: Parser<'a, '_>) -> ParseResult<(Self, ParserConsumed<'a>)> {
31        // Parse the attribute list.
32        let mut attribute_list = Vec::new();
33        while let Some(DocComment { .. }) = parser.peek() {
34            let doc_comment = parser.parse::<DocComment>()?;
35            // TODO: Use a Literal instead of an Ident when Attribute args
36            // start supporting them and remove `Ident::new_no_trim`.
37            let name = Ident::new_no_trim(doc_comment.content_span.clone());
38            match &doc_comment.doc_style {
39                DocStyle::Inner => attribute_list.push(AttributeDecl {
40                    hash_kind: AttributeHashKind::Inner(HashBangToken::new(
41                        doc_comment.span.clone(),
42                    )),
43                    attribute: SquareBrackets::new(
44                        Punctuated::single(Attribute {
45                            name: Ident::new_with_override(
46                                DOC_COMMENT_ATTRIBUTE_NAME.to_string(),
47                                doc_comment.span.clone(),
48                            ),
49                            args: Some(Parens::new(
50                                Punctuated::single(AttributeArg { name, value: None }),
51                                doc_comment.content_span,
52                            )),
53                        }),
54                        doc_comment.span,
55                    ),
56                }),
57                DocStyle::Outer => {
58                    parser.emit_error(ParseErrorKind::ExpectedModuleDocComment);
59                }
60            }
61        }
62        let (kind, semicolon_token) = parser.parse()?;
63        let (items, consumed) = parser.parse_to_end()?;
64        let module = Annotated {
65            attribute_list,
66            value: Module {
67                kind,
68                semicolon_token,
69                items,
70            },
71        };
72        Ok((module, consumed))
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79    use crate::test_utils::parse_to_end;
80    use insta::*;
81
82    #[test]
83    fn parse_noop_script_module() {
84        assert_ron_snapshot!(parse_to_end::<Annotated<Module>>(r#"
85            script;
86        
87            fn main() {
88                ()
89            }
90        "#,), @r#"
91        Annotated(
92          attribute_list: [],
93          value: Module(
94            kind: Script(
95              script_token: ScriptToken(
96                span: Span(
97                  src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
98                  start: 13,
99                  end: 19,
100                  source_id: None,
101                ),
102              ),
103            ),
104            semicolon_token: SemicolonToken(
105              span: Span(
106                src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
107                start: 19,
108                end: 20,
109                source_id: None,
110              ),
111            ),
112            items: [
113              Annotated(
114                attribute_list: [],
115                value: Fn(ItemFn(
116                  fn_signature: FnSignature(
117                    visibility: None,
118                    fn_token: FnToken(
119                      span: Span(
120                        src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
121                        start: 42,
122                        end: 44,
123                        source_id: None,
124                      ),
125                    ),
126                    name: BaseIdent(
127                      name_override_opt: None,
128                      span: Span(
129                        src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
130                        start: 45,
131                        end: 49,
132                        source_id: None,
133                      ),
134                      is_raw_ident: false,
135                    ),
136                    generics: None,
137                    arguments: Parens(
138                      inner: Static(Punctuated(
139                        value_separator_pairs: [],
140                        final_value_opt: None,
141                      )),
142                      span: Span(
143                        src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
144                        start: 49,
145                        end: 51,
146                        source_id: None,
147                      ),
148                    ),
149                    return_type_opt: None,
150                    where_clause_opt: None,
151                  ),
152                  body: Braces(
153                    inner: CodeBlockContents(
154                      statements: [],
155                      final_expr_opt: Some(Tuple(Parens(
156                        inner: Nil,
157                        span: Span(
158                          src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
159                          start: 70,
160                          end: 72,
161                          source_id: None,
162                        ),
163                      ))),
164                      span: Span(
165                        src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
166                        start: 53,
167                        end: 85,
168                        source_id: None,
169                      ),
170                    ),
171                    span: Span(
172                      src: "\n            script;\n        \n            fn main() {\n                ()\n            }\n        ",
173                      start: 52,
174                      end: 86,
175                      source_id: None,
176                    ),
177                  ),
178                )),
179              ),
180            ],
181          ),
182        )
183        "#);
184    }
185}