Skip to main content

dada_parser/
classes.rs

1use dada_ir_ast::{
2    ast::{
3        AstAggregate, AstAggregateKind, AstFieldDecl, AstFunction, AstGenericDecl, AstMember,
4        AstTy, AstTyKind, AstVisibility, AstWhereClauses, SpanVec, VariableDecl, VisibilityKind,
5    },
6    span::{Span, Spanned},
7};
8use salsa::Update;
9
10use crate::{ParseFail, tokenizer::operator};
11
12use super::{
13    Expected, Parse, Parser,
14    miscellaneous::OrOptParse,
15    tokenizer::{Delimiter, Keyword},
16};
17
18/// class Name { ... }
19impl<'db> Parse<'db> for AstAggregate<'db> {
20    type Output = Self;
21
22    fn opt_parse(
23        db: &'db dyn crate::Db,
24        parser: &mut Parser<'_, 'db>,
25    ) -> Result<Option<Self>, ParseFail<'db>> {
26        if !AstAggregatePrefix::can_eat(db, parser) {
27            return Ok(None);
28        }
29
30        let start = parser.peek_span();
31
32        let AstAggregatePrefix {
33            visibility,
34            aggregate_kind,
35            aggregate_keyword: _,
36        } = AstAggregatePrefix::eat(db, parser)?;
37
38        let id = parser.eat_id()?;
39
40        let generics = AstGenericDecl::opt_parse_delimited(
41            db,
42            parser,
43            Delimiter::SquareBrackets,
44            AstGenericDecl::eat_comma,
45        )?;
46
47        let inputs = AstFieldDecl::opt_parse_delimited(
48            db,
49            parser,
50            Delimiter::Parentheses,
51            AstFieldDecl::eat_comma,
52        )?;
53
54        let where_clauses = AstWhereClauses::opt_parse(db, parser)?;
55
56        let body = parser.defer_delimited(Delimiter::CurlyBraces).ok();
57
58        Ok(Some(AstAggregate::new(
59            db,
60            start.to(db, parser.last_span()),
61            visibility,
62            aggregate_kind,
63            id.id,
64            id.span,
65            generics,
66            inputs,
67            where_clauses,
68            body,
69        )))
70    }
71
72    fn expected() -> Expected {
73        Expected::Keyword(Keyword::Class)
74    }
75}
76
77/// The *prefix* parses a class declaration up until
78/// the `class` keyword. That is what we need to see
79/// to know that we should be parsing a class.
80/// Parsing always succeeds with `Ok(Some)` or errors;
81/// the intent is that you probe with `can_eat`.
82#[derive(Update)]
83struct AstAggregatePrefix<'db> {
84    /// Visibility of the class
85    visibility: Option<AstVisibility<'db>>,
86    aggregate_kind: AstAggregateKind,
87    aggregate_keyword: Span<'db>,
88}
89
90impl<'db> Parse<'db> for AstAggregatePrefix<'db> {
91    type Output = Self;
92
93    fn opt_parse(
94        db: &'db dyn crate::Db,
95        parser: &mut Parser<'_, 'db>,
96    ) -> Result<Option<Self>, ParseFail<'db>> {
97        let visibility = AstVisibility::opt_parse(db, parser)?;
98
99        if let Ok(span) = parser.eat_keyword(Keyword::Class) {
100            Ok(Some(AstAggregatePrefix {
101                visibility,
102                aggregate_kind: AstAggregateKind::Class,
103                aggregate_keyword: span,
104            }))
105        } else if let Ok(span) = parser.eat_keyword(Keyword::Struct) {
106            Ok(Some(AstAggregatePrefix {
107                visibility,
108                aggregate_kind: AstAggregateKind::Struct,
109                aggregate_keyword: span,
110            }))
111        } else {
112            Ok(None)
113        }
114    }
115
116    fn expected() -> Expected {
117        Expected::Nonterminal("class")
118    }
119}
120
121#[salsa::tracked]
122impl<'db> crate::prelude::ClassItemMembers<'db> for AstAggregate<'db> {
123    #[salsa::tracked(return_ref)]
124    fn members(self, db: &'db dyn crate::Db) -> SpanVec<'db, AstMember<'db>> {
125        if let Some(contents) = self.contents(db) {
126            Parser::deferred(db, self, contents, |parser| {
127                parser.parse_many_and_report_diagnostics::<AstMember<'db>>(db)
128            })
129        } else {
130            SpanVec {
131                span: self.span(db).at_end(),
132                values: vec![],
133            }
134        }
135    }
136}
137
138impl<'db> Parse<'db> for AstMember<'db> {
139    type Output = Self;
140
141    fn opt_parse(
142        db: &'db dyn crate::Db,
143        parser: &mut Parser<'_, 'db>,
144    ) -> Result<Option<Self>, super::ParseFail<'db>> {
145        // Subtle: ordering is important here.
146        // We prefer to parse members that have distinctive keywords
147        // first (e.g., `fn`) because they are able to return `Ok(None)` when
148        // that keyword is not present, allowing easier detection of which
149        // form is correct. In principle we could modify `AstFieldDecl`'s parser
150        // to fail more gracefully, but it's easier to just reorder things here.
151        AstFunction::opt_parse(db, parser).or_opt_parse::<Self, AstFieldDecl<'db>>(db, parser)
152    }
153
154    fn expected() -> Expected {
155        Expected::Nonterminal("class member")
156    }
157}
158
159impl<'db> Parse<'db> for AstFieldDecl<'db> {
160    type Output = Self;
161
162    fn opt_parse(
163        db: &'db dyn crate::Db,
164        tokens: &mut Parser<'_, 'db>,
165    ) -> Result<Option<Self>, super::ParseFail<'db>> {
166        let visibility = AstVisibility::opt_parse(db, tokens)?;
167
168        let variable = match VariableDecl::opt_parse(db, tokens) {
169            Ok(Some(v)) => v,
170            Ok(None) => {
171                return if visibility.is_some() {
172                    Err(tokens.illformed(VariableDecl::expected()))
173                } else {
174                    Ok(None)
175                };
176            }
177            Err(e) => return Err(e),
178        };
179
180        Ok(Some(AstFieldDecl::new(
181            db,
182            visibility
183                .as_ref()
184                .map(|v| v.span)
185                .unwrap_or_else(|| variable.span(db))
186                .to(db, variable.span(db)),
187            visibility,
188            variable,
189        )))
190    }
191
192    fn expected() -> Expected {
193        Expected::Nonterminal("variable declaration")
194    }
195}
196
197impl<'db> Parse<'db> for AstVisibility<'db> {
198    type Output = Self;
199
200    fn opt_parse(
201        _db: &'db dyn crate::Db,
202        tokens: &mut Parser<'_, 'db>,
203    ) -> Result<Option<Self>, super::ParseFail<'db>> {
204        if let Ok(span) = tokens.eat_keyword(Keyword::Pub) {
205            return Ok(Some(AstVisibility {
206                span,
207                kind: VisibilityKind::Pub,
208            }));
209        }
210
211        if let Ok(span) = tokens.eat_keyword(Keyword::Export) {
212            return Ok(Some(AstVisibility {
213                span,
214                kind: VisibilityKind::Export,
215            }));
216        }
217
218        Ok(None)
219    }
220
221    fn expected() -> Expected {
222        Expected::Nonterminal("visibility")
223    }
224}
225
226impl<'db> Parse<'db> for VariableDecl<'db> {
227    type Output = Self;
228
229    fn opt_parse(
230        db: &'db dyn crate::Db,
231        tokens: &mut Parser<'_, 'db>,
232    ) -> Result<Option<Self>, super::ParseFail<'db>> {
233        let (mutable, name);
234        if let Ok(span) = tokens.eat_keyword(Keyword::Mut) {
235            mutable = Some(span);
236            name = tokens.eat_id()?;
237        } else if let Ok(id) = tokens.eat_id() {
238            mutable = None;
239            name = id;
240        } else {
241            return Ok(None);
242        };
243
244        let _ = tokens.eat_op(operator::COLON)?;
245
246        let ty = AstTy::eat(db, tokens)?;
247
248        let (perm, base_ty) = match ty.kind(db) {
249            AstTyKind::Perm(ast_perm, ast_ty) => (Some(ast_perm), ast_ty),
250            AstTyKind::Named(..) => (None, ty),
251            AstTyKind::GenericDecl(..) => (None, ty),
252        };
253
254        Ok(Some(VariableDecl::new(db, mutable, name, perm, base_ty)))
255    }
256
257    fn expected() -> Expected {
258        Expected::Nonterminal("variable declaration")
259    }
260}