1use salsa::Update;
2
3use dada_ir_ast::{
4 ast::{
5 AstGenericDecl, AstGenericKind, AstGenericTerm, AstPath, AstPerm, AstPermKind, AstTy,
6 AstTyKind, SpanVec,
7 },
8 span::{Span, Spanned},
9};
10
11use super::{
12 Expected, Parse, ParseFail, Parser,
13 tokenizer::{Delimiter, Keyword},
14};
15
16#[derive(Debug, Update)]
19enum TyOrPerm<'db> {
20 Path(AstPath<'db>, Option<SpanVec<'db, AstGenericTerm<'db>>>),
22
23 Generic(AstGenericDecl<'db>),
25
26 PermKeyword(AstPerm<'db>),
28
29 Apply(AstPerm<'db>, AstTy<'db>),
31}
32
33impl<'db> Parse<'db> for TyOrPerm<'db> {
34 type Output = Self;
35
36 fn opt_parse(
37 db: &'db dyn crate::Db,
38 parser: &mut Parser<'_, 'db>,
39 ) -> Result<Option<Self::Output>, ParseFail<'db>> {
40 if let Some(path) = AstPath::opt_parse(db, parser)? {
41 let generic_args = AstGenericTerm::opt_parse_delimited(
42 db,
43 parser,
44 Delimiter::SquareBrackets,
45 AstGenericTerm::eat_comma,
46 )?;
47
48 return TyOrPerm::Path(path, generic_args).maybe_apply(db, parser);
49 }
50
51 if let Some(generic_decl) = AstGenericDecl::opt_parse(db, parser)? {
52 return TyOrPerm::Generic(generic_decl).maybe_apply(db, parser);
53 };
54
55 if let Some(p) = KeywordPerm::opt_parse(db, parser)? {
56 return TyOrPerm::PermKeyword(p).maybe_apply(db, parser);
57 }
58
59 Ok(None)
60 }
61
62 fn expected() -> Expected {
63 Expected::Nonterminal("type or permission")
64 }
65}
66
67impl<'db> Spanned<'db> for TyOrPerm<'db> {
68 fn span(&self, db: &'db dyn crate::Db) -> Span<'db> {
69 match self {
70 TyOrPerm::Path(path, args) => {
71 let args_span = args.as_ref().map(|a| a.span);
72 path.span(db).to(db, args_span)
73 }
74 TyOrPerm::Generic(decl) => decl.span(db),
75 TyOrPerm::PermKeyword(p) => p.span(db),
76 TyOrPerm::Apply(p, ty) => p.span(db).to(db, ty.span(db)),
77 }
78 }
79}
80
81impl<'db> TyOrPerm<'db> {
82 fn maybe_apply(
84 self,
85 db: &'db dyn crate::Db,
86 parser: &mut Parser<'_, 'db>,
87 ) -> Result<Option<Self>, ParseFail<'db>> {
88 if self.can_be_perm(db)
89 && parser.next_token_on_same_line()
90 && let Some(ty) = AstTy::opt_parse(db, parser)?
91 {
92 let perm = self.into_perm(db).unwrap();
93 return Ok(Some(TyOrPerm::Apply(perm, ty)));
94 }
95
96 Ok(Some(self))
97 }
98
99 fn can_be_perm(&self, db: &'db dyn crate::Db) -> bool {
101 match self {
102 TyOrPerm::Path(path, None) => path.len(db) == 1,
103 TyOrPerm::Path(_path, Some(_)) => false,
104 TyOrPerm::Generic(decl) => matches!(decl.kind(db), AstGenericKind::Perm(_)),
105 TyOrPerm::PermKeyword(_) => true,
106 TyOrPerm::Apply(_, _) => false,
107 }
108 }
109
110 fn into_perm(self, db: &'db dyn crate::Db) -> Option<AstPerm<'db>> {
111 match self {
112 TyOrPerm::Path(path, None) if path.len(db) == 1 => {
113 let id = path.first_id(db);
114 Some(AstPerm::new(db, id.span, AstPermKind::Variable(id)))
115 }
116 TyOrPerm::Path(..) => None,
117 TyOrPerm::Generic(decl) => match decl.kind(db) {
118 AstGenericKind::Perm(_) => Some(AstPerm::new(
119 db,
120 decl.span(db),
121 AstPermKind::GenericDecl(decl),
122 )),
123 _ => None,
124 },
125 TyOrPerm::PermKeyword(p) => Some(p),
126 TyOrPerm::Apply(_, _) => None,
127 }
128 }
129
130 fn can_be_ty(&self, db: &'db dyn crate::Db) -> bool {
132 match self {
133 TyOrPerm::Path(..) => true,
134 TyOrPerm::Generic(decl) => matches!(decl.kind(db), AstGenericKind::Type(_)),
135 TyOrPerm::PermKeyword(_) => false,
136 TyOrPerm::Apply(_, _) => true,
137 }
138 }
139
140 fn into_ty(self, db: &'db dyn crate::Db) -> Option<AstTy<'db>> {
141 let span = self.span(db);
142 match self {
143 TyOrPerm::Path(path, args) => Some(AstTy::new(db, span, AstTyKind::Named(path, args))),
144 TyOrPerm::Generic(decl) => match decl.kind(db) {
145 AstGenericKind::Type(_) => Some(AstTy::new(db, span, AstTyKind::GenericDecl(decl))),
146 _ => None,
147 },
148 TyOrPerm::PermKeyword(_) => None,
149 TyOrPerm::Apply(p, t) => Some(AstTy::new(db, span, AstTyKind::Perm(p, t))),
150 }
151 }
152}
153
154impl<'db> Parse<'db> for AstTy<'db> {
155 type Output = Self;
156
157 fn opt_parse(
158 db: &'db dyn crate::Db,
159 parser: &mut Parser<'_, 'db>,
160 ) -> Result<Option<Self>, ParseFail<'db>> {
161 let Some(ty_or_perm) = TyOrPerm::opt_parse(db, parser)? else {
162 return Ok(None);
163 };
164
165 let span = ty_or_perm.span(db);
166
167 if let Some(ty) = ty_or_perm.into_ty(db) {
168 return Ok(Some(ty));
169 }
170
171 Err(ParseFail::Expected(span, Self::expected()))
172 }
173
174 fn expected() -> Expected {
175 Expected::Nonterminal("type")
176 }
177}
178
179impl<'db> Parse<'db> for AstPerm<'db> {
180 type Output = Self;
181
182 fn opt_parse(
183 db: &'db dyn crate::Db,
184 parser: &mut Parser<'_, 'db>,
185 ) -> Result<Option<Self>, ParseFail<'db>> {
186 let Some(ty_or_perm) = TyOrPerm::opt_parse(db, parser)? else {
187 return Ok(None);
188 };
189
190 let span = ty_or_perm.span(db);
191
192 if let Some(perm) = ty_or_perm.into_perm(db) {
193 return Ok(Some(perm));
194 }
195
196 Err(ParseFail::Expected(span, Self::expected()))
197 }
198
199 fn expected() -> Expected {
200 Expected::Nonterminal("permission")
201 }
202}
203
204struct KeywordPerm;
205
206impl<'db> Parse<'db> for KeywordPerm {
207 type Output = AstPerm<'db>;
208
209 fn opt_parse(
210 db: &'db dyn crate::Db,
211 tokens: &mut Parser<'_, 'db>,
212 ) -> Result<Option<AstPerm<'db>>, ParseFail<'db>> {
213 if let Ok(span) = tokens.eat_keyword(Keyword::Ref) {
214 Ok(Some(parse_path_perm(
215 db,
216 span,
217 tokens,
218 AstPermKind::Referenced,
219 )?))
220 } else if let Ok(span) = tokens.eat_keyword(Keyword::Mut) {
221 Ok(Some(parse_path_perm(
222 db,
223 span,
224 tokens,
225 AstPermKind::Mutable,
226 )?))
227 } else if let Ok(span) = tokens.eat_keyword(Keyword::Given) {
228 Ok(Some(parse_path_perm(db, span, tokens, AstPermKind::Given)?))
229 } else if let Ok(span) = tokens.eat_keyword(Keyword::My) {
230 Ok(Some(AstPerm::new(db, span, AstPermKind::My)))
231 } else if let Ok(span) = tokens.eat_keyword(Keyword::Our) {
232 Ok(Some(AstPerm::new(db, span, AstPermKind::Our)))
233 } else {
234 Ok(None)
235 }
236 }
237
238 fn expected() -> Expected {
239 AstPerm::expected()
240 }
241}
242
243fn parse_path_perm<'db>(
244 db: &'db dyn crate::Db,
245 span: Span<'db>,
246 parser: &mut Parser<'_, 'db>,
247 op: impl Fn(Option<SpanVec<'db, AstPath<'db>>>) -> AstPermKind<'db>,
248) -> Result<AstPerm<'db>, ParseFail<'db>> {
249 let paths =
250 AstPath::opt_parse_delimited(db, parser, Delimiter::SquareBrackets, AstPath::eat_comma)?;
251 let kind = op(paths);
252 Ok(AstPerm::new(db, span.to(db, parser.last_span()), kind))
253}
254
255impl<'db> Parse<'db> for AstGenericTerm<'db> {
256 type Output = AstGenericTerm<'db>;
257
258 fn opt_parse(
259 db: &'db dyn crate::Db,
260 parser: &mut Parser<'_, 'db>,
261 ) -> Result<Option<Self::Output>, ParseFail<'db>> {
262 let Some(ty_or_perm) = TyOrPerm::opt_parse(db, parser)? else {
263 return Ok(None);
264 };
265
266 match ty_or_perm {
267 TyOrPerm::Path(path, None) if path.len(db) == 1 => {
269 Ok(Some(AstGenericTerm::Id(path.first_id(db))))
270 }
271
272 TyOrPerm::Generic(_)
274 | TyOrPerm::PermKeyword(_)
275 | TyOrPerm::Path(..)
276 | TyOrPerm::Apply(_, _) => {
277 let can_be_perm = ty_or_perm.can_be_perm(db);
278 let can_be_ty = ty_or_perm.can_be_ty(db);
279
280 if can_be_perm {
281 assert!(!can_be_ty);
282 Ok(Some(ty_or_perm.into_perm(db).unwrap().into()))
283 } else {
284 assert!(can_be_ty);
285 Ok(Some(ty_or_perm.into_ty(db).unwrap().into()))
286 }
287 }
288 }
289 }
290
291 fn expected() -> Expected {
292 Expected::Nonterminal("type or permission")
293 }
294}