1use dada_ir_ast::{
2 ast::{
3 AstBlock, AstExpr, AstFunction, AstFunctionEffects, AstFunctionInput, AstGenericDecl,
4 AstLetStatement, AstPerm, AstSelfArg, AstStatement, AstTy, AstVisibility, AstWhereClauses,
5 SpanVec, VariableDecl,
6 },
7 diagnostic::{Diagnostic, Level},
8 span::Span,
9};
10use salsa::Update;
11
12use crate::{
13 Expected, Parse, ParseFail, Parser,
14 miscellaneous::OrOptParse,
15 tokenizer::{Delimiter, Keyword, operator},
16};
17
18impl<'db> Parse<'db> for AstFunction<'db> {
19 type Output = Self;
20
21 fn opt_parse(
22 db: &'db dyn crate::Db,
23 parser: &mut Parser<'_, 'db>,
24 ) -> Result<Option<Self>, super::ParseFail<'db>> {
25 if !AstFunctionPrefix::can_eat(db, parser) {
26 return Ok(None);
27 }
28
29 let start_span = parser.peek_span();
30
31 let AstFunctionPrefix {
32 visibility,
33 effects,
34 fn_keyword: fn_span,
35 } = AstFunctionPrefix::eat(db, parser)?;
36
37 let name = parser.eat_id()?;
38
39 let generics = AstGenericDecl::opt_parse_delimited(
40 db,
41 parser,
42 Delimiter::SquareBrackets,
43 AstGenericDecl::eat_comma,
44 )?;
45
46 let arguments = AstFunctionInput::eat_delimited(
48 db,
49 parser,
50 Delimiter::Parentheses,
51 AstFunctionInput::opt_parse_comma,
52 )?;
53 let arguments = match arguments {
54 Some(arguments) => arguments,
55 None => SpanVec {
56 span: parser.last_span(),
57 values: vec![],
58 },
59 };
60
61 let return_ty = AstTy::opt_parse_guarded(operator::ARROW, db, parser)?;
62
63 let where_clauses = AstWhereClauses::opt_parse(db, parser)?;
64
65 let body = parser.defer_delimited(Delimiter::CurlyBraces).ok();
66
67 Ok(Some(AstFunction::new(
68 db,
69 start_span.to(db, parser.last_span()),
70 effects,
71 fn_span,
72 visibility,
73 name,
74 generics,
75 arguments,
76 return_ty,
77 where_clauses,
78 body,
79 )))
80 }
81
82 fn expected() -> Expected {
83 Expected::Nonterminal("`fn`")
84 }
85}
86
87#[derive(Update)]
93struct AstFunctionPrefix<'db> {
94 visibility: Option<AstVisibility<'db>>,
96 effects: AstFunctionEffects<'db>,
97 fn_keyword: Span<'db>,
98}
99
100impl<'db> Parse<'db> for AstFunctionPrefix<'db> {
101 type Output = Self;
102
103 fn opt_parse(
104 db: &'db dyn crate::Db,
105 parser: &mut Parser<'_, 'db>,
106 ) -> Result<Option<Self>, ParseFail<'db>> {
107 Ok(Some(AstFunctionPrefix {
108 visibility: AstVisibility::opt_parse(db, parser)?,
109 effects: AstFunctionEffects::eat(db, parser)?,
110 fn_keyword: parser.eat_keyword(Keyword::Fn)?,
111 }))
112 }
113
114 fn expected() -> Expected {
115 Expected::Nonterminal("fn")
116 }
117}
118
119impl<'db> Parse<'db> for AstFunctionEffects<'db> {
120 type Output = Self;
121
122 fn opt_parse(
123 db: &'db dyn crate::Db,
124 parser: &mut Parser<'_, 'db>,
125 ) -> Result<Option<Self>, super::ParseFail<'db>> {
126 let mut effects = AstFunctionEffects::default();
127
128 loop {
129 if let Ok(span) = parser.eat_keyword(Keyword::Async) {
130 if let Some(prev_span) = effects.async_effect {
131 report_duplicate_keyword(db, "async", span, prev_span);
132 }
133 effects.async_effect = Some(span);
134 continue;
135 }
136
137 if let Ok(span) = parser.eat_keyword(Keyword::Unsafe) {
138 if let Some(prev_span) = effects.unsafe_effect {
139 report_duplicate_keyword(db, "unsafe", span, prev_span);
140 }
141 effects.unsafe_effect = Some(span);
142 continue;
143 }
144
145 break;
146 }
147
148 Ok(Some(effects))
149 }
150
151 fn expected() -> Expected {
152 Expected::Nonterminal("function effects")
153 }
154}
155
156fn report_duplicate_keyword<'db>(
157 db: &'db dyn crate::Db,
158 kw: &str,
159 span: Span<'db>,
160 prev_span: Span<'db>,
161) {
162 Diagnostic::error(db, span, format!("duplicate `{kw}` keyword"))
163 .label(
164 db,
165 Level::Error,
166 span,
167 format!("`{kw}` keyword already specified"),
168 )
169 .label(
170 db,
171 Level::Error,
172 prev_span,
173 format!("previous `{kw}` keyword"),
174 )
175 .report(db);
176}
177
178impl<'db> Parse<'db> for AstFunctionInput<'db> {
179 type Output = Self;
180
181 fn opt_parse(
182 db: &'db dyn crate::Db,
183 parser: &mut Parser<'_, 'db>,
184 ) -> Result<Option<Self>, super::ParseFail<'db>> {
185 if AstSelfArg::can_eat(db, parser) {
186 Ok(Some(AstSelfArg::eat(db, parser)?.into()))
187 } else if let Some(v) = VariableDecl::opt_parse(db, parser)? {
188 Ok(Some(v.into()))
189 } else {
190 Ok(None)
191 }
192 }
193
194 fn expected() -> Expected {
195 Expected::Nonterminal("function argument")
196 }
197}
198
199impl<'db> Parse<'db> for AstSelfArg<'db> {
200 type Output = Self;
201
202 fn opt_parse(
203 db: &'db dyn crate::Db,
204 parser: &mut Parser<'_, 'db>,
205 ) -> Result<Option<Self>, super::ParseFail<'db>> {
206 if let Some(perm) = AstPerm::opt_parse(db, parser)? {
208 let self_span = parser.eat_keyword(Keyword::Self_)?;
209 Ok(Some(AstSelfArg::new(db, Some(perm), self_span)))
210 } else if let Ok(span) = parser.eat_keyword(Keyword::Self_) {
211 Ok(Some(AstSelfArg::new(db, None, span)))
213 } else {
214 Ok(None)
216 }
217 }
218
219 fn expected() -> Expected {
220 Expected::Nonterminal("self argument")
221 }
222}
223
224#[salsa::tracked]
225impl<'db> crate::prelude::FunctionBlock<'db> for AstFunction<'db> {
226 #[salsa::tracked]
227 fn body_block(self, db: &'db dyn crate::Db) -> Option<AstBlock<'db>> {
228 let body = self.body(db).as_ref()?;
229 Some(Parser::deferred(db, self, body, |parser| {
230 let statements = parser.parse_many_and_report_diagnostics::<AstStatement>(db);
231 AstBlock::new(db, statements)
232 }))
233 }
234}
235
236impl<'db> Parse<'db> for AstBlock<'db> {
237 type Output = Self;
238
239 fn opt_parse(
240 db: &'db dyn crate::Db,
241 parser: &mut Parser<'_, 'db>,
242 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
243 let Some(statements) = AstStatement::opt_parse_delimited(
244 db,
245 parser,
246 crate::tokenizer::Delimiter::CurlyBraces,
247 AstStatement::eat_many,
248 )?
249 else {
250 return Ok(None);
251 };
252
253 Ok(Some(AstBlock::new(db, statements)))
254 }
255
256 fn expected() -> crate::Expected {
257 crate::Expected::Nonterminal("block")
258 }
259}
260
261impl<'db> Parse<'db> for AstStatement<'db> {
262 type Output = Self;
263
264 fn opt_parse(
265 db: &'db dyn crate::Db,
266 parser: &mut Parser<'_, 'db>,
267 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
268 AstLetStatement::opt_parse(db, parser).or_opt_parse::<Self, AstExpr>(db, parser)
269 }
270
271 fn expected() -> crate::Expected {
272 crate::Expected::Nonterminal("statement")
273 }
274}
275
276impl<'db> Parse<'db> for AstLetStatement<'db> {
277 type Output = Self;
278
279 fn opt_parse(
280 db: &'db dyn crate::Db,
281 parser: &mut Parser<'_, 'db>,
282 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
283 let Ok(let_span) = parser.eat_keyword(Keyword::Let) else {
284 return Ok(None);
285 };
286 let mutable = parser.eat_keyword(Keyword::Mut).ok();
287 let name = parser.eat_id()?;
288 let ty = AstTy::opt_parse_guarded(operator::COLON, db, parser)?;
289 let initializer = AstExpr::opt_parse_guarded(operator::EQ, db, parser)?;
290 Ok(Some(AstLetStatement::new(
291 db,
292 let_span.to(db, parser.last_span()),
293 mutable,
294 name,
295 ty,
296 initializer,
297 )))
298 }
299
300 fn expected() -> crate::Expected {
301 crate::Expected::Nonterminal("let statement")
302 }
303}