1use dada_ir_ast::ast::{
2 AstBinaryOp, AstBlock, AstConstructorField, AstExpr, AstExprKind, AstPath, AstPathKind,
3 DeferredParse, Identifier, IfArm, Literal, LiteralKind, PermissionOp, SpannedBinaryOp,
4 SpannedIdentifier, SpannedUnaryOp, SquareBracketArgs, UnaryOp,
5};
6
7use crate::{
8 Parse, Parser,
9 tokenizer::{
10 Keyword, Token, TokenKind,
11 operator::{self, Op},
12 },
13};
14
15impl<'db> Parse<'db> for AstExpr<'db> {
16 type Output = Self;
17
18 fn opt_parse(
19 db: &'db dyn crate::Db,
20 parser: &mut Parser<'_, 'db>,
21 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
22 opt_parse_expr_with_precedence(db, parser, binary_expr_precedence::<SELECT_ALL>)
23 }
24
25 fn expected() -> crate::Expected {
26 crate::Expected::Nonterminal("expression")
27 }
28}
29
30const SELECT_ALL: u32 = u32::MAX;
31const SELECT_STRUCT: u32 = 1;
32
33fn eat_expr_with_precedence<'db>(
34 db: &'db dyn crate::Db,
35 parser: &mut Parser<'_, 'db>,
36 precedence: impl FnOnce(
37 &'db dyn crate::Db,
38 &mut Parser<'_, 'db>,
39 ) -> Result<Option<AstExprKind<'db>>, crate::ParseFail<'db>>,
40) -> Result<AstExpr<'db>, crate::ParseFail<'db>> {
41 match opt_parse_expr_with_precedence(db, parser, precedence)? {
42 Some(e) => Ok(e),
43 None => Err(parser.illformed(AstExpr::expected())),
44 }
45}
46
47fn opt_parse_expr_with_precedence<'db>(
48 db: &'db dyn crate::Db,
49 parser: &mut Parser<'_, 'db>,
50 precedence: impl FnOnce(
51 &'db dyn crate::Db,
52 &mut Parser<'_, 'db>,
53 ) -> Result<Option<AstExprKind<'db>>, crate::ParseFail<'db>>,
54) -> Result<Option<AstExpr<'db>>, crate::ParseFail<'db>> {
55 let start_span = parser.peek_span();
56 let Some(kind) = precedence(db, parser)? else {
57 return Ok(None);
58 };
59 Ok(Some(AstExpr::new(
60 start_span.to(db, parser.last_span()),
61 kind,
62 )))
63}
64
65const BINARY_OP_PRECEDENCE: &[&[(Op, AstBinaryOp)]] = &[
66 &[
67 (operator::PLUS, AstBinaryOp::Add),
68 (operator::MINUS, AstBinaryOp::Sub),
69 ],
70 &[
71 (operator::STAR, AstBinaryOp::Mul),
72 (operator::SLASH, AstBinaryOp::Div),
73 ],
74 &[
75 (operator::GREATERTHANEQ, AstBinaryOp::GreaterEqual),
76 (operator::LESSTHANEQ, AstBinaryOp::LessEqual),
77 (operator::GREATERTHAN, AstBinaryOp::GreaterThan),
78 (operator::LESSTHAN, AstBinaryOp::LessThan),
79 (operator::EQEQ, AstBinaryOp::EqualEqual),
80 ],
81 &[(operator::ANDAND, AstBinaryOp::AndAnd)],
82 &[(operator::PIPEPIPE, AstBinaryOp::OrOr)],
83 &[(operator::EQ, AstBinaryOp::Assign)],
84];
85
86fn binary_expr_precedence<'db, const SELECT: u32>(
87 db: &'db dyn crate::Db,
88 parser: &mut Parser<'_, 'db>,
89) -> Result<Option<AstExprKind<'db>>, crate::ParseFail<'db>> {
90 binary_expr_with_precedence_level::<SELECT>(db, parser, 0)
91}
92
93fn binary_expr_with_precedence_level<'db, const SELECT: u32>(
94 db: &'db dyn crate::Db,
95 parser: &mut Parser<'_, 'db>,
96 precedence: usize,
97) -> Result<Option<AstExprKind<'db>>, crate::ParseFail<'db>> {
98 let start_span = parser.peek_span();
99
100 if precedence >= BINARY_OP_PRECEDENCE.len() {
101 return postfix_expr_precedence::<SELECT>(db, parser);
102 }
103
104 let Some(mut lhs_kind) =
107 binary_expr_with_precedence_level::<SELECT>(db, parser, precedence + 1)?
108 else {
109 return Ok(None);
110 };
111
112 'outer: loop {
117 let mid_span = parser.peek_span();
118
119 if parser.next_token_on_same_line() {
120 for &(op_text, op) in BINARY_OP_PRECEDENCE[precedence] {
121 if let Ok(op_span) = parser.eat_op(op_text) {
122 let lhs = AstExpr::new(start_span.to(db, mid_span), lhs_kind);
123 let rhs = eat_expr_with_precedence(db, parser, |db, parser| {
124 binary_expr_with_precedence_level::<SELECT>(db, parser, precedence)
126 })?;
127 lhs_kind =
128 AstExprKind::BinaryOp(SpannedBinaryOp { span: op_span, op }, lhs, rhs);
129 continue 'outer;
130 }
131 }
132 }
133
134 return Ok(Some(lhs_kind));
135 }
136}
137
138fn postfix_expr_precedence<'db, const SELECT: u32>(
139 db: &'db dyn crate::Db,
140 parser: &mut Parser<'_, 'db>,
141) -> Result<Option<AstExprKind<'db>>, crate::ParseFail<'db>> {
142 let start_span = parser.peek_span();
143
144 let Some(mut kind) = base_expr_precedence::<SELECT>(db, parser)? else {
145 return Ok(None);
146 };
147
148 loop {
149 let mid_span = parser.last_span();
150
151 if parser.eat_op(operator::DOT).is_ok() {
153 if let Ok(id) = parser.eat_id() {
154 let owner = AstExpr::new(start_span.to(db, mid_span), kind);
155 kind = AstExprKind::DotId(owner, id);
156 continue;
157 }
158
159 if let Ok(await_keyword) = parser.eat_keyword(Keyword::Await) {
160 let future = AstExpr::new(start_span.to(db, mid_span), kind);
161 kind = AstExprKind::Await {
162 future,
163 await_keyword,
164 };
165 continue;
166 }
167
168 if let Some(op) = PermissionOp::opt_parse(db, parser)? {
169 let value = AstExpr::new(start_span.to(db, mid_span), kind);
170 kind = AstExprKind::PermissionOp { value, op };
171 continue;
172 }
173 }
174
175 if parser.next_token_on_same_line()
177 && let Ok(text) = parser.eat_delimited(crate::tokenizer::Delimiter::SquareBrackets)
178 {
179 let owner = AstExpr::new(start_span.to(db, mid_span), kind);
180 let deferred = DeferredParse {
181 span: parser.last_span(),
182 contents: text.to_string(),
183 };
184 let args = SquareBracketArgs::new(db, deferred);
185 kind = AstExprKind::SquareBracketOp(owner, args);
186 continue;
187 }
188
189 if parser.next_token_on_same_line()
191 && let Some(args) = AstExpr::opt_parse_delimited(
192 db,
193 parser,
194 crate::tokenizer::Delimiter::Parentheses,
195 AstExpr::eat_comma,
196 )?
197 {
198 let owner = AstExpr::new(start_span.to(db, mid_span), kind);
199 kind = AstExprKind::ParenthesisOp(owner, args);
200 continue;
201 }
202
203 return Ok(Some(kind));
204 }
205}
206
207fn base_expr_precedence<'db, const SELECT: u32>(
229 db: &'db dyn crate::Db,
230 parser: &mut Parser<'_, 'db>,
231) -> Result<Option<AstExprKind<'db>>, crate::ParseFail<'db>> {
232 if let Some(literal) = Literal::opt_parse(db, parser)? {
233 return Ok(Some(AstExprKind::Literal(literal)));
234 }
235
236 if let Ok(if_span) = parser.eat_keyword(Keyword::If) {
237 return Ok(Some(if_chain(db, parser, if_span)?));
238 }
239
240 if let Ok(id) = parser.eat_id() {
241 if (SELECT & SELECT_STRUCT != 0)
243 && parser.next_token_on_same_line()
244 && let Some(fields) = AstConstructorField::opt_parse_delimited(
245 db,
246 parser,
247 crate::tokenizer::Delimiter::CurlyBraces,
248 AstConstructorField::eat_comma,
249 )?
250 {
251 let path = AstPath::new(db, AstPathKind::Identifier(id));
252 return Ok(Some(AstExprKind::Constructor(path, fields)));
253 }
254
255 return Ok(Some(AstExprKind::Id(id)));
256 }
257
258 if let Ok(span) = parser.eat_keyword(Keyword::Self_) {
259 let id = SpannedIdentifier {
260 span,
261 id: Identifier::self_ident(db),
262 };
263 return Ok(Some(AstExprKind::Id(id)));
264 }
265
266 if parser.eat_keyword(Keyword::Return).is_ok() {
267 if parser.next_token_on_same_line()
269 && let Some(expr) = AstExpr::opt_parse(db, parser)?
270 {
271 return Ok(Some(AstExprKind::Return(Some(expr))));
272 }
273 return Ok(Some(AstExprKind::Return(None)));
274 }
275
276 if let Ok(span) = parser.eat_op(operator::BANG) {
277 let expr = eat_expr_with_precedence(db, parser, postfix_expr_precedence::<SELECT>)?;
278 return Ok(Some(AstExprKind::UnaryOp(
279 SpannedUnaryOp {
280 span,
281 op: UnaryOp::Not,
282 },
283 expr,
284 )));
285 }
286
287 if let Ok(span) = parser.eat_op(operator::MINUS) {
288 let expr = eat_expr_with_precedence(db, parser, postfix_expr_precedence::<SELECT>)?;
289 return Ok(Some(AstExprKind::UnaryOp(
290 SpannedUnaryOp {
291 span,
292 op: UnaryOp::Negate,
293 },
294 expr,
295 )));
296 }
297
298 Ok(None)
299}
300
301fn if_chain<'db>(
302 db: &'db dyn crate::Db,
303 parser: &mut Parser<'_, 'db>,
304 _if_span: dada_ir_ast::span::Span<'db>,
305) -> Result<AstExprKind<'db>, crate::ParseFail<'db>> {
306 let condition0 = eat_expr_with_precedence(
307 db,
308 parser,
309 binary_expr_precedence::<{ SELECT_ALL - SELECT_STRUCT }>,
310 )?;
311
312 let block0 = AstBlock::eat(db, parser)?;
313
314 let mut arms = vec![IfArm {
315 condition: Some(condition0),
316 result: block0,
317 }];
318
319 while parser.eat_keyword(Keyword::Else).is_ok() {
320 if let Ok(_if_span) = parser.eat_keyword(Keyword::If) {
321 let else_if_condition = eat_expr_with_precedence(
322 db,
323 parser,
324 binary_expr_precedence::<{ SELECT_ALL - SELECT_STRUCT }>,
325 )?;
326 let else_if_block = AstBlock::eat(db, parser)?;
327 arms.push(IfArm {
328 condition: Some(else_if_condition),
329 result: else_if_block,
330 });
331 } else {
332 let else_block = AstBlock::eat(db, parser)?;
333 arms.push(IfArm {
334 condition: None,
335 result: else_block,
336 });
337 break;
338 }
339 }
340
341 Ok(AstExprKind::If(arms))
342}
343
344impl<'db> Parse<'db> for PermissionOp {
345 type Output = Self;
346
347 fn opt_parse(
348 _db: &'db dyn crate::Db,
349 parser: &mut Parser<'_, 'db>,
350 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
351 if parser.eat_keyword(Keyword::Give).is_ok() {
352 Ok(Some(PermissionOp::Give))
353 } else if parser.eat_keyword(Keyword::Mut).is_ok() {
354 Ok(Some(PermissionOp::Mutate))
355 } else if parser.eat_keyword(Keyword::Ref).is_ok() {
356 Ok(Some(PermissionOp::Reference))
357 } else if parser.eat_keyword(Keyword::Share).is_ok() {
358 Ok(Some(PermissionOp::Share))
359 } else {
360 Ok(None)
361 }
362 }
363
364 fn expected() -> crate::Expected {
365 crate::Expected::Nonterminal("permission operator")
366 }
367}
368
369impl<'db> Parse<'db> for Literal<'db> {
370 type Output = Self;
371
372 fn opt_parse(
394 db: &'db dyn crate::Db,
395 parser: &mut Parser<'_, 'db>,
396 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
397 match parser.peek() {
398 Some(Token {
399 kind: TokenKind::Literal(kind, token_text),
400 ..
401 }) => {
402 let literal = Literal::new(db, *kind, token_text.text(db).clone());
403
404 parser.eat_next_token().unwrap();
405
406 Ok(Some(literal))
407 }
408
409 Some(Token {
410 kind: TokenKind::Keyword(Keyword::True),
411 ..
412 }) => {
413 parser.eat_next_token().unwrap();
414 Ok(Some(Literal::new(db, LiteralKind::Boolean, "true")))
415 }
416
417 Some(Token {
418 kind: TokenKind::Keyword(Keyword::False),
419 ..
420 }) => {
421 parser.eat_next_token().unwrap();
422 Ok(Some(Literal::new(db, LiteralKind::Boolean, "false")))
423 }
424
425 _ => Ok(None),
426 }
427 }
428
429 fn expected() -> crate::Expected {
430 crate::Expected::Nonterminal("literal")
431 }
432}
433
434impl<'db> Parse<'db> for AstConstructorField<'db> {
435 type Output = Self;
436
437 fn opt_parse(
438 db: &'db dyn crate::Db,
439 parser: &mut Parser<'_, 'db>,
440 ) -> Result<Option<Self::Output>, crate::ParseFail<'db>> {
441 let Ok(name) = parser.eat_id() else {
442 return Ok(None);
443 };
444
445 let _colon = parser.eat_op(operator::COLON)?;
446
447 let value = AstExpr::eat(db, parser)?;
448
449 Ok(Some(AstConstructorField { name, value }))
450 }
451
452 fn expected() -> crate::Expected {
453 crate::Expected::Nonterminal("field initializer")
454 }
455}