1use super::expressions::parse_expr;
2use super::functions::parse_fn_def;
3use super::types::{
4 parse_impl_def, parse_path_tail, parse_struct_def, parse_trait_def, parse_type_alias,
5 parse_type_desc,
6};
7use super::{contracts::parse_contract_def, types::parse_enum_def};
8use crate::ast::{ConstantDecl, Module, ModuleStmt, Pragma, Use, UseTree};
9use crate::node::{Node, Span};
10use crate::{Label, ParseFailed, ParseResult, Parser, TokenKind};
11
12use semver::VersionReq;
13
14pub fn parse_module(par: &mut Parser) -> Node<Module> {
16 let mut body = vec![];
17 loop {
18 match par.peek() {
19 Some(TokenKind::Newline) => {
20 par.next().unwrap();
21 }
22 None => break,
23 Some(_) => {
24 match parse_module_stmt(par) {
25 Ok(stmt) => body.push(stmt),
26 Err(_) => {
27 body.push(ModuleStmt::ParseError(Span::zero(par.file_id)));
29 break;
30 }
31 };
32 }
33 }
34 }
35 let span = Span::zero(par.file_id) + body.first() + body.last();
36 Node::new(Module { body }, span)
37}
38
39pub fn parse_module_stmt(par: &mut Parser) -> ParseResult<ModuleStmt> {
41 let stmt = match par.peek_or_err()? {
42 TokenKind::Pragma => ModuleStmt::Pragma(parse_pragma(par)?),
43 TokenKind::Use => ModuleStmt::Use(parse_use(par)?),
44 TokenKind::Contract => ModuleStmt::Contract(parse_contract_def(par, None)?),
45 TokenKind::Struct => ModuleStmt::Struct(parse_struct_def(par, None)?),
46 TokenKind::Enum => ModuleStmt::Enum(parse_enum_def(par, None)?),
47 TokenKind::Trait => ModuleStmt::Trait(parse_trait_def(par, None)?),
48 TokenKind::Impl => ModuleStmt::Impl(parse_impl_def(par)?),
49 TokenKind::Type => ModuleStmt::TypeAlias(parse_type_alias(par, None)?),
50 TokenKind::Const => ModuleStmt::Constant(parse_constant(par, None)?),
51 TokenKind::Pub => {
52 let pub_span = par.next()?.span;
53 match par.peek_or_err()? {
54 TokenKind::Fn | TokenKind::Unsafe => {
55 ModuleStmt::Function(parse_fn_def(par, Some(pub_span))?)
56 }
57 TokenKind::Struct => ModuleStmt::Struct(parse_struct_def(par, Some(pub_span))?),
58 TokenKind::Enum => ModuleStmt::Enum(parse_enum_def(par, Some(pub_span))?),
59 TokenKind::Trait => ModuleStmt::Trait(parse_trait_def(par, Some(pub_span))?),
60 TokenKind::Type => ModuleStmt::TypeAlias(parse_type_alias(par, Some(pub_span))?),
61 TokenKind::Const => ModuleStmt::Constant(parse_constant(par, Some(pub_span))?),
62 TokenKind::Contract => {
63 ModuleStmt::Contract(parse_contract_def(par, Some(pub_span))?)
64 }
65 _ => {
66 let tok = par.next()?;
67 par.unexpected_token_error(
68 &tok,
69 "failed to parse module",
70 vec!["Note: expected `fn`".into()],
71 );
72 return Err(ParseFailed);
73 }
74 }
75 }
76 TokenKind::Fn | TokenKind::Unsafe => ModuleStmt::Function(parse_fn_def(par, None)?),
77 TokenKind::Hash => {
78 let attr = par.expect(TokenKind::Hash, "expected `#`")?;
79 let attr_name = par.expect_with_notes(TokenKind::Name, "failed to parse attribute definition", |_|
80 vec!["Note: an attribute name must start with a letter or underscore, and contain letters, numbers, or underscores".into()])?;
81 ModuleStmt::Attribute(Node::new(attr_name.text.into(), attr.span + attr_name.span))
82 }
83 _ => {
84 let tok = par.next()?;
85 par.unexpected_token_error(
86 &tok,
87 "failed to parse module",
88 vec!["Note: expected import, contract, struct, type or const".into()],
89 );
90 return Err(ParseFailed);
91 }
92 };
93 Ok(stmt)
94}
95
96pub fn parse_constant(par: &mut Parser, pub_qual: Option<Span>) -> ParseResult<Node<ConstantDecl>> {
100 let const_tok = par.assert(TokenKind::Const);
101 let name = par.expect(TokenKind::Name, "failed to parse constant declaration")?;
102 par.expect_with_notes(
103 TokenKind::Colon,
104 "failed to parse constant declaration",
105 |_| {
106 vec![
107 "Note: constant name must be followed by a colon and a type description".into(),
108 format!("Example: let `{}: u256 = 1000`", name.text),
109 ]
110 },
111 )?;
112 let typ = parse_type_desc(par)?;
113 par.expect_with_notes(
114 TokenKind::Eq,
115 "failed to parse constant declaration",
116 |_| {
117 vec![
118 "Note: the type of a constant must be followed by an equals sign and a value assignment"
119 .into(),
120 format!(
121 "Example: let `{}: u256 = 1000`",
122 name.text
123 ),
124 ]
125 },
126 )?;
127
128 let exp = parse_expr(par)?;
129
130 let span = const_tok.span + exp.span;
131 Ok(Node::new(
132 ConstantDecl {
133 name: name.into(),
134 typ,
135 value: exp,
136 pub_qual,
137 },
138 span,
139 ))
140}
141
142pub fn parse_use(par: &mut Parser) -> ParseResult<Node<Use>> {
146 let use_tok = par.assert(TokenKind::Use);
147
148 let tree = parse_use_tree(par)?;
149 let tree_span = tree.span;
150
151 Ok(Node::new(Use { tree }, use_tok.span + tree_span))
152}
153
154pub fn parse_use_tree(par: &mut Parser) -> ParseResult<Node<UseTree>> {
156 let (path, path_span, trailing_delim) = {
157 let path_head =
158 par.expect_with_notes(TokenKind::Name, "failed to parse `use` statement", |_| {
159 vec![
160 "Note: `use` paths must start with a name".into(),
161 "Example: `use foo::bar`".into(),
162 ]
163 })?;
164 parse_path_tail(par, path_head.into())
165 };
166
167 if trailing_delim.is_some() {
168 match par.peek() {
169 Some(TokenKind::BraceOpen) => {
170 par.next()?;
171
172 let mut children = vec![];
173 let close_brace_span;
174
175 loop {
176 children.push(parse_use_tree(par)?);
177 let tok = par.next()?;
178 match tok.kind {
179 TokenKind::Comma => {
180 continue;
181 }
182 TokenKind::BraceClose => {
183 close_brace_span = tok.span;
184 break;
185 }
186 _ => {
187 par.unexpected_token_error(
188 &tok,
189 "failed to parse `use` tree",
190 vec!["Note: expected a `,` or `}` token".to_string()],
191 );
192 return Err(ParseFailed);
193 }
194 }
195 }
196
197 Ok(Node::new(
198 UseTree::Nested {
199 prefix: path,
200 children,
201 },
202 close_brace_span,
203 ))
204 }
205 Some(TokenKind::Star) => {
206 par.next()?;
207 Ok(Node::new(UseTree::Glob { prefix: path }, path_span))
208 }
209 _ => {
210 let tok = par.next()?;
211 par.unexpected_token_error(
212 &tok,
213 "failed to parse `use` tree",
214 vec!["Note: expected a `*`, `{` or name token".to_string()],
215 );
216 Err(ParseFailed)
217 }
218 }
219 } else if par.peek() == Some(TokenKind::As) {
220 par.next()?;
221
222 let rename_tok = par.expect(TokenKind::Name, "failed to parse `use` tree")?;
223 let span = path_span + rename_tok.span;
224 let rename = Some(rename_tok.into());
225
226 Ok(Node::new(UseTree::Simple { path, rename }, span))
227 } else {
228 Ok(Node::new(UseTree::Simple { path, rename: None }, path_span))
229 }
230}
231
232pub fn parse_pragma(par: &mut Parser) -> ParseResult<Node<Pragma>> {
234 let tok = par.assert(TokenKind::Pragma);
235 assert_eq!(tok.text, "pragma");
236
237 let mut version_string = String::new();
238 let mut tokens = vec![];
239 loop {
240 match par.peek() {
241 Some(TokenKind::Newline) => break,
242 None => break,
243 _ => {
244 let tok = par.next()?;
245 version_string.push_str(tok.text);
246 tokens.push(tok);
247 }
248 }
249 }
250
251 let version_requirement_span = match (tokens.first(), tokens.last()) {
252 (Some(first), Some(last)) => first.span + last.span,
253 _ => {
254 par.error(
255 tok.span,
256 "failed to parse pragma statement: missing version requirement",
257 );
258 return Err(ParseFailed);
259 }
260 };
261
262 match VersionReq::parse(&version_string) {
263 Ok(_) => Ok(Node::new(
264 Pragma {
265 version_requirement: Node::new(version_string.into(), version_requirement_span),
266 },
267 tok.span + version_requirement_span,
268 )),
269 Err(err) => {
270 par.fancy_error(
271 format!("failed to parse pragma statement: {err}"),
272 vec![Label::primary(
273 version_requirement_span,
274 "Invalid version requirement",
275 )],
276 vec!["Example: `^0.5.0`".into()],
277 );
278 Err(ParseFailed)
279 }
280 }
281}