1mod atom;
2
3use crate::grammar::attributes::ATTRIBUTE_FIRST;
4
5use super::*;
6
7pub(super) use atom::{EXPR_RECOVERY_SET, LITERAL_FIRST, literal, parse_asm_expr};
8pub(crate) use atom::{block_expr, match_arm_list};
9
10#[derive(PartialEq, Eq)]
11pub(super) enum Semicolon {
12 Required,
13 Optional,
14 Forbidden,
15}
16
17const EXPR_FIRST: TokenSet = LHS_FIRST;
18
19pub(super) fn expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
20 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
21 expr_bp(p, None, r, 1).map(|(m, _)| m)
22}
23
24pub(super) fn expr_stmt(
25 p: &mut Parser<'_>,
26 m: Option<Marker>,
27) -> Option<(CompletedMarker, BlockLike)> {
28 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
29 expr_bp(p, m, r, 1)
30}
31
32fn expr_no_struct(p: &mut Parser<'_>) {
33 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
34 expr_bp(p, None, r, 1);
35}
36
37fn expr_let(p: &mut Parser<'_>) {
42 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
43 expr_bp(p, None, r, 5);
44}
45
46pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
47 if p.eat(T![;]) {
48 return;
49 }
50
51 let m = p.start();
52 attributes::outer_attrs(p);
60
61 if p.at(T![let]) || (p.at(T![super]) && p.nth_at(1, T![let])) {
62 let_stmt(p, semicolon);
63 m.complete(p, LET_STMT);
64 return;
65 }
66
67 let m = match items::opt_item(p, m, false) {
70 Ok(()) => return,
71 Err(m) => m,
72 };
73
74 if !p.at_ts(EXPR_FIRST) {
75 p.err_and_bump("expected expression, item or let statement");
76 m.abandon(p);
77 return;
78 }
79
80 if let Some((cm, blocklike)) = expr_stmt(p, Some(m))
81 && !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF)))
82 {
83 let m = cm.precede(p);
98 match semicolon {
99 Semicolon::Required => {
100 if blocklike.is_block() {
101 p.eat(T![;]);
102 } else {
103 p.expect(T![;]);
104 }
105 }
106 Semicolon::Optional => {
107 p.eat(T![;]);
108 }
109 Semicolon::Forbidden => (),
110 }
111 m.complete(p, EXPR_STMT);
112 }
113}
114
115pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) {
118 p.eat(T![super]);
119 p.bump(T![let]);
120 patterns::pattern(p);
121 if p.at(T![:]) {
122 types::ascription(p);
125 }
126
127 let mut expr_after_eq: Option<CompletedMarker> = None;
128 if p.eat(T![=]) {
129 expr_after_eq = expressions::expr(p);
132 }
133
134 if p.at(T![else]) {
135 if let Some(expr) = expr_after_eq
138 && let Some(token) = expr.last_token(p)
139 && token == T!['}']
140 {
141 p.error("right curly brace `}` before `else` in a `let...else` statement not allowed")
142 }
143
144 let m = p.start();
147 p.bump(T![else]);
148 block_expr(p);
149 m.complete(p, LET_ELSE);
150 }
151
152 match with_semi {
153 Semicolon::Forbidden => (),
154 Semicolon::Optional => {
155 p.eat(T![;]);
156 }
157 Semicolon::Required => {
158 p.expect(T![;]);
159 }
160 }
161}
162
163pub(super) fn expr_block_contents(p: &mut Parser<'_>) {
164 attributes::inner_attrs(p);
165
166 while !p.at(EOF) && !p.at(T!['}']) {
167 stmt(p, Semicolon::Required);
182 }
183}
184
185#[derive(Clone, Copy)]
186struct Restrictions {
187 forbid_structs: bool,
188 prefer_stmt: bool,
189}
190
191enum Associativity {
192 Left,
193 Right,
194}
195
196#[rustfmt::skip]
203fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity) {
204 use Associativity::*;
205 const NOT_AN_OP: (u8, SyntaxKind, Associativity) = (0, T![@], Left);
206 match p.current() {
207 T![|] if p.at(T![||]) => (3, T![||], Left),
208 T![|] if p.at(T![|=]) => (1, T![|=], Right),
209 T![|] => (6, T![|], Left),
210 T![>] if p.at(T![>>=]) => (1, T![>>=], Right),
211 T![>] if p.at(T![>>]) => (9, T![>>], Left),
212 T![>] if p.at(T![>=]) => (5, T![>=], Left),
213 T![>] => (5, T![>], Left),
214 T![=] if p.at(T![==]) => (5, T![==], Left),
215 T![=] if !p.at(T![=>]) => (1, T![=], Right),
216 T![<] if p.at(T![<=]) => (5, T![<=], Left),
217 T![<] if p.at(T![<<=]) => (1, T![<<=], Right),
218 T![<] if p.at(T![<<]) => (9, T![<<], Left),
219 T![<] => (5, T![<], Left),
220 T![+] if p.at(T![+=]) => (1, T![+=], Right),
221 T![+] => (10, T![+], Left),
222 T![^] if p.at(T![^=]) => (1, T![^=], Right),
223 T![^] => (7, T![^], Left),
224 T![%] if p.at(T![%=]) => (1, T![%=], Right),
225 T![%] => (11, T![%], Left),
226 T![&] if p.at(T![&=]) => (1, T![&=], Right),
227 T![&] if p.at(T![&&]) => (4, T![&&], Left),
229 T![&] => (8, T![&], Left),
230 T![/] if p.at(T![/=]) => (1, T![/=], Right),
231 T![/] => (11, T![/], Left),
232 T![*] if p.at(T![*=]) => (1, T![*=], Right),
233 T![*] => (11, T![*], Left),
234 T![.] if p.at(T![..=]) => (2, T![..=], Left),
235 T![.] if p.at(T![..]) => (2, T![..], Left),
236 T![!] if p.at(T![!=]) => (5, T![!=], Left),
237 T![-] if p.at(T![-=]) => (1, T![-=], Right),
238 T![-] => (10, T![-], Left),
239 T![as] => (12, T![as], Left),
240
241 _ => NOT_AN_OP
242 }
243}
244
245fn expr_bp(
247 p: &mut Parser<'_>,
248 m: Option<Marker>,
249 r: Restrictions,
250 bp: u8,
251) -> Option<(CompletedMarker, BlockLike)> {
252 let m = m.unwrap_or_else(|| {
253 let m = p.start();
254 attributes::outer_attrs(p);
255 m
256 });
257
258 if !p.at_ts(EXPR_FIRST) {
259 p.err_recover("expected expression", atom::EXPR_RECOVERY_SET);
260 m.abandon(p);
261 return None;
262 }
263 let mut lhs = match lhs(p, r) {
264 Some((lhs, blocklike)) => {
265 let lhs = lhs.extend_to(p, m);
266 if r.prefer_stmt && blocklike.is_block() {
267 return Some((lhs, BlockLike::Block));
273 }
274 lhs
275 }
276 None => {
277 m.abandon(p);
278 return None;
279 }
280 };
281
282 loop {
283 let is_range = p.at(T![..]) || p.at(T![..=]);
284 let (op_bp, op, associativity) = current_op(p);
285 if op_bp < bp {
286 break;
287 }
288 if p.at(T![as]) {
291 lhs = cast_expr(p, lhs);
292 continue;
293 }
294 let m = lhs.precede(p);
295 p.bump(op);
296
297 if is_range {
298 let has_trailing_expression =
305 p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
306 if !has_trailing_expression {
307 lhs = m.complete(p, RANGE_EXPR);
309 break;
310 }
311 }
312
313 let op_bp = match associativity {
314 Associativity::Left => op_bp + 1,
315 Associativity::Right => op_bp,
316 };
317
318 expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp);
321 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
322 }
323 Some((lhs, BlockLike::NotBlock))
324}
325
326const LHS_FIRST: TokenSet =
327 atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-], T![_]]));
328
329fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
330 let m;
331 let kind = match p.current() {
332 T![&] => {
345 m = p.start();
346 p.bump(T![&]);
347 if p.at_contextual_kw(T![raw]) {
348 if [T![mut], T![const]].contains(&p.nth(1)) {
349 p.bump_remap(T![raw]);
350 p.bump_any();
351 } else if p.nth_at(1, SyntaxKind::IDENT) {
352 p.bump_remap(T![raw]);
355 }
356 } else {
357 p.eat(T![mut]);
358 }
359 REF_EXPR
360 }
361 T![*] | T![!] | T![-] => {
368 m = p.start();
369 p.bump_any();
370 PREFIX_EXPR
371 }
372 _ => {
373 for op in [T![..=], T![..]] {
376 if p.at(op) {
377 m = p.start();
378 p.bump(op);
379
380 let has_access_after = p.at(T![.]) && p.nth_at(1, SyntaxKind::IDENT);
386 let struct_forbidden = r.forbid_structs && p.at(T!['{']);
387 if p.at_ts(EXPR_FIRST) && !has_access_after && !struct_forbidden {
388 expr_bp(p, None, r, 2);
389 }
390 let cm = m.complete(p, RANGE_EXPR);
391 return Some((cm, BlockLike::NotBlock));
392 }
393 }
394
395 let (lhs, blocklike) = atom::atom_expr(p, r)?;
401 let (cm, block_like) =
402 postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
403 return Some((cm, block_like));
404 }
405 };
406 expr_bp(p, None, r, 255);
408 let cm = m.complete(p, kind);
409 Some((cm, BlockLike::NotBlock))
410}
411
412fn postfix_expr(
413 p: &mut Parser<'_>,
414 mut lhs: CompletedMarker,
415 mut block_like: BlockLike,
419 mut allow_calls: bool,
420) -> (CompletedMarker, BlockLike) {
421 loop {
422 lhs = match p.current() {
423 T!['('] if allow_calls => call_expr(p, lhs),
432 T!['['] if allow_calls => index_expr(p, lhs),
433 T![.] => match postfix_dot_expr::<false>(p, lhs) {
439 Ok(it) => it,
440 Err(it) => {
441 lhs = it;
442 break;
443 }
444 },
445 T![?] => try_expr(p, lhs),
446 _ => break,
447 };
448 allow_calls = true;
449 block_like = BlockLike::NotBlock;
450 }
451 (lhs, block_like)
452}
453
454fn postfix_dot_expr<const FLOAT_RECOVERY: bool>(
455 p: &mut Parser<'_>,
456 lhs: CompletedMarker,
457) -> Result<CompletedMarker, CompletedMarker> {
458 if !FLOAT_RECOVERY {
459 assert!(p.at(T![.]));
460 }
461 let nth1 = if FLOAT_RECOVERY { 0 } else { 1 };
462 let nth2 = if FLOAT_RECOVERY { 1 } else { 2 };
463
464 if PATH_NAME_REF_KINDS.contains(p.nth(nth1))
465 && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::]))
466 || p.nth(nth1) == T!['(']
467 {
468 return Ok(method_call_expr::<FLOAT_RECOVERY>(p, lhs));
469 }
470
471 if p.nth(nth1) == T![await] {
480 let m = lhs.precede(p);
481 if !FLOAT_RECOVERY {
482 p.bump(T![.]);
483 }
484 p.bump(T![await]);
485 return Ok(m.complete(p, AWAIT_EXPR));
486 }
487
488 if p.at(T![..=]) || p.at(T![..]) {
489 return Err(lhs);
490 }
491
492 field_expr::<FLOAT_RECOVERY>(p, lhs)
493}
494
495fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
503 assert!(p.at(T!['(']));
504 let m = lhs.precede(p);
505 arg_list(p);
506 m.complete(p, CALL_EXPR)
507}
508
509fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
514 assert!(p.at(T!['[']));
515 let m = lhs.precede(p);
516 p.bump(T!['[']);
517 expr(p);
518 p.expect(T![']']);
519 m.complete(p, INDEX_EXPR)
520}
521
522fn method_call_expr<const FLOAT_RECOVERY: bool>(
531 p: &mut Parser<'_>,
532 lhs: CompletedMarker,
533) -> CompletedMarker {
534 if FLOAT_RECOVERY {
535 assert!(
536 p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))
537 || p.current() == T!['(']
538 );
539 } else {
540 assert!(p.at(T![.]));
541 assert!(
542 PATH_NAME_REF_KINDS.contains(p.nth(1)) && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
543 || p.nth(1) == T!['(']
544 );
545 }
546 let m = lhs.precede(p);
547 if !FLOAT_RECOVERY {
548 p.bump(T![.]);
549 }
550 if p.at_ts(PATH_NAME_REF_KINDS) {
551 name_ref_mod_path(p);
552 } else {
553 p.error("expected method name, field name or number");
554 }
555 generic_args::opt_generic_arg_list_expr(p);
556 if p.at(T!['(']) {
557 arg_list(p);
558 } else {
559 p.error("expected argument list");
567 }
568 m.complete(p, METHOD_CALL_EXPR)
569}
570
571fn field_expr<const FLOAT_RECOVERY: bool>(
582 p: &mut Parser<'_>,
583 lhs: CompletedMarker,
584) -> Result<CompletedMarker, CompletedMarker> {
585 if !FLOAT_RECOVERY {
586 assert!(p.at(T![.]));
587 }
588 let m = lhs.precede(p);
589 if !FLOAT_RECOVERY {
590 p.bump(T![.]);
591 }
592 if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) {
593 name_ref_mod_path_or_index(p);
594 } else if p.at(FLOAT_NUMBER) {
595 return match p.split_float(m) {
596 (true, m) => {
597 let lhs = m.complete(p, FIELD_EXPR);
598 postfix_dot_expr::<true>(p, lhs)
599 }
600 (false, m) => Ok(m.complete(p, FIELD_EXPR)),
601 };
602 } else {
603 p.error("expected field name or number");
604 }
605 Ok(m.complete(p, FIELD_EXPR))
606}
607
608fn try_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
613 assert!(p.at(T![?]));
614 let m = lhs.precede(p);
615 p.bump(T![?]);
616 m.complete(p, TRY_EXPR)
617}
618
619fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
627 assert!(p.at(T![as]));
628 let m = lhs.precede(p);
629 p.bump(T![as]);
630 types::type_no_bounds(p);
633 m.complete(p, CAST_EXPR)
634}
635
636fn arg_list(p: &mut Parser<'_>) {
644 assert!(p.at(T!['(']));
645 let m = p.start();
646 delimited(
651 p,
652 T!['('],
653 T![')'],
654 T![,],
655 || "expected expression".into(),
656 EXPR_FIRST.union(ATTRIBUTE_FIRST),
657 |p| expr(p).is_some(),
658 );
659 m.complete(p, ARG_LIST);
660}
661
662fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike) {
670 assert!(paths::is_path_start(p));
671 let m = p.start();
672 paths::expr_path(p);
673 match p.current() {
674 T!['{'] if !r.forbid_structs => {
675 record_expr_field_list(p);
676 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
677 }
678 T![!] if !p.at(T![!=]) => {
679 let block_like = items::macro_call_after_excl(p);
680 (m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_EXPR), block_like)
681 }
682 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
683 }
684}
685
686pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
698 assert!(p.at(T!['{']));
699 let m = p.start();
700 p.bump(T!['{']);
701 while !p.at(EOF) && !p.at(T!['}']) {
702 let m = p.start();
703 attributes::outer_attrs(p);
708
709 match p.current() {
710 IDENT | INT_NUMBER if p.nth_at(1, T![::]) => {
711 m.abandon(p);
717 p.expect(T![..]);
718 expr(p);
719 }
720 IDENT | INT_NUMBER if p.nth_at(1, T![..]) => {
721 name_ref_or_index(p);
729 p.error("expected `:`");
730 m.complete(p, RECORD_EXPR_FIELD);
731 }
732 IDENT | INT_NUMBER => {
733 if p.nth_at(1, T![:]) {
739 name_ref_or_index(p);
740 p.bump(T![:]);
741 } else if p.nth_at(1, T![=]) {
742 name_ref_or_index(p);
743 p.err_and_bump("expected `:`");
744 }
745 expr(p);
746 m.complete(p, RECORD_EXPR_FIELD);
747 }
748 T![.] if p.at(T![..]) => {
749 m.abandon(p);
750 p.bump(T![..]);
751
752 if !p.at(T!['}']) {
765 expr(p);
766
767 if p.at(T![,]) {
768 p.error("cannot use a comma after the base struct");
782 }
783 }
784 }
785 T!['{'] => {
786 error_block(p, "expected a field");
787 m.abandon(p);
788 }
789 _ => {
790 p.err_and_bump("expected identifier");
791 m.abandon(p);
792 }
793 }
794 if !p.at(T!['}']) {
795 p.expect(T![,]);
796 }
797 }
798 p.expect(T!['}']);
799 m.complete(p, RECORD_EXPR_FIELD_LIST);
800}