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 let mut attribute_list = Vec::new();
33 while let Some(DocComment { .. }) = parser.peek() {
34 let doc_comment = parser.parse::<DocComment>()?;
35 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}