Skip to main content

dada_parser/
functions.rs

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        // Parse the arguments, accepting an empty list.
47        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/// The *prefix* parses a fn declaration up until
88/// the `fn` keyword. That is what we need to see
89/// to know that we should be parsing a function.
90/// Parsing always succeeds with `Ok(Some)` or errors;
91/// the intent is that you probe with `can_eat`.
92#[derive(Update)]
93struct AstFunctionPrefix<'db> {
94    /// Visibility of the class
95    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 we see a perm, this *must* be self...
207        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            // ...otherwise, it could be self...
212            Ok(Some(AstSelfArg::new(db, None, span)))
213        } else {
214            // ...otherwise it ain't.
215            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}