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
18impl<'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#[derive(Update)]
83struct AstAggregatePrefix<'db> {
84 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 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}