5 pub(crate) use self::atom::{block_expr, match_arm_list};
6 pub(super) use self::atom::{literal, LITERAL_FIRST};
8 pub(super) enum StmtWithSemi {
14 const EXPR_FIRST: TokenSet = LHS_FIRST;
16 pub(super) fn expr(p: &mut Parser) -> bool {
17 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
18 expr_bp(p, None, r, 1).is_some()
21 pub(super) fn expr_stmt(p: &mut Parser, m: Option<Marker>) -> Option<(CompletedMarker, BlockLike)> {
22 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
26 fn expr_no_struct(p: &mut Parser) {
27 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
28 expr_bp(p, None, r, 1);
31 pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
33 // test attr_on_expr_stmt
40 attributes::outer_attrs(p);
43 let_stmt(p, m, with_semi);
48 // fn a() { fn b() {} }
49 let m = match items::opt_item(p, m) {
54 if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
55 if !(p.at(T!['}']) || (prefer_expr && p.at(EOF))) {
56 // test no_semi_after_block
65 // macro_rules! test {
70 let m = cm.precede(p);
72 StmtWithSemi::No => (),
73 StmtWithSemi::Optional => {
76 StmtWithSemi::Yes => {
77 if blocklike.is_block() {
85 m.complete(p, EXPR_STMT);
90 // fn f() { let x: i32 = 92; }
91 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
95 // test let_stmt_ascription
96 // fn f() { let x: i32; }
100 // test let_stmt_init
101 // fn f() { let x = 92; }
102 expressions::expr(p);
107 // fn f() { let Some(x) = opt else { return }; }
112 m.complete(p, LET_ELSE);
116 StmtWithSemi::No => (),
117 StmtWithSemi::Optional => {
120 StmtWithSemi::Yes => {
124 m.complete(p, LET_STMT);
128 pub(super) fn expr_block_contents(p: &mut Parser) {
129 attributes::inner_attrs(p);
131 while !p.at(EOF) && !p.at(T!['}']) {
132 // test nocontentexpr
134 // ;;;some_expr();;;;{;;;};;;;Ok(())
137 // test nocontentexpr_after_item
138 // fn simple_function() {
152 stmt(p, StmtWithSemi::Yes, false);
156 #[derive(Clone, Copy)]
157 struct Restrictions {
158 forbid_structs: bool,
162 /// Binding powers of operators for a Pratt parser.
164 /// See <https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html>
166 fn current_op(p: &Parser) -> (u8, SyntaxKind) {
167 const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]);
169 T![|] if p.at(T![||]) => (3, T![||]),
170 T![|] if p.at(T![|=]) => (1, T![|=]),
172 T![>] if p.at(T![>>=]) => (1, T![>>=]),
173 T![>] if p.at(T![>>]) => (9, T![>>]),
174 T![>] if p.at(T![>=]) => (5, T![>=]),
176 T![=] if p.at(T![=>]) => NOT_AN_OP,
177 T![=] if p.at(T![==]) => (5, T![==]),
179 T![<] if p.at(T![<=]) => (5, T![<=]),
180 T![<] if p.at(T![<<=]) => (1, T![<<=]),
181 T![<] if p.at(T![<<]) => (9, T![<<]),
183 T![+] if p.at(T![+=]) => (1, T![+=]),
184 T![+] => (10, T![+]),
185 T![^] if p.at(T![^=]) => (1, T![^=]),
187 T![%] if p.at(T![%=]) => (1, T![%=]),
188 T![%] => (11, T![%]),
189 T![&] if p.at(T![&=]) => (1, T![&=]),
190 T![&] if p.at(T![&&]) => (4, T![&&]),
192 T![/] if p.at(T![/=]) => (1, T![/=]),
193 T![/] => (11, T![/]),
194 T![*] if p.at(T![*=]) => (1, T![*=]),
195 T![*] => (11, T![*]),
196 T![.] if p.at(T![..=]) => (2, T![..=]),
197 T![.] if p.at(T![..]) => (2, T![..]),
198 T![!] if p.at(T![!=]) => (5, T![!=]),
199 T![-] if p.at(T![-=]) => (1, T![-=]),
200 T![-] => (10, T![-]),
201 T![as] => (12, T![as]),
207 // Parses expression with binding power of at least bp.
213 ) -> Option<(CompletedMarker, BlockLike)> {
214 let m = m.unwrap_or_else(|| {
216 attributes::outer_attrs(p);
219 let mut lhs = match lhs(p, r) {
220 Some((lhs, blocklike)) => {
221 let lhs = lhs.extend_to(p, m);
222 if r.prefer_stmt && blocklike.is_block() {
223 // test stmt_bin_expr_ambiguity
228 return Some((lhs, BlockLike::Block));
239 let is_range = p.at(T![..]) || p.at(T![..=]);
240 let (op_bp, op) = current_op(p);
244 // test as_precedence
245 // fn f() { let _ = &1 as *const i32; }
247 lhs = cast_expr(p, lhs);
250 let m = lhs.precede(p);
253 // test binop_resets_statementness
254 // fn f() { v = {1}&2; }
255 r = Restrictions { prefer_stmt: false, ..r };
258 // test postfix_range
261 // match 1.. { _ => () };
262 // match a.b()..S { _ => () };
264 let has_trailing_expression =
265 p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
266 if !has_trailing_expression {
268 lhs = m.complete(p, RANGE_EXPR);
273 expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
274 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
276 Some((lhs, BlockLike::NotBlock))
279 const LHS_FIRST: TokenSet =
280 atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-]]));
282 fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
284 let kind = match p.current() {
287 // // reference operator
289 // let _ = &mut &f();
292 // // raw reference operator
293 // let _ = &raw mut foo;
294 // let _ = &raw const foo;
299 if p.at_contextual_kw(T![raw]) && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) {
300 p.bump_remap(T![raw]);
313 T![*] | T![!] | T![-] => {
319 // test full_range_expr
320 // fn foo() { xs[..]; }
321 for op in [T![..=], T![..]] {
325 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
326 expr_bp(p, None, r, 2);
328 let cm = m.complete(p, RANGE_EXPR);
329 return Some((cm, BlockLike::NotBlock));
333 // test expression_after_block
335 // let mut p = F{x: 5};
338 let (lhs, blocklike) = atom::atom_expr(p, r)?;
339 let (cm, block_like) =
340 postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
341 return Some((cm, block_like));
344 // parse the interior of the unary expression
345 expr_bp(p, None, r, 255);
346 let cm = m.complete(p, kind);
347 Some((cm, BlockLike::NotBlock))
352 mut lhs: CompletedMarker,
353 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
354 // E.g. `while true {break}();` is parsed as
355 // `while true {break}; ();`
356 mut block_like: BlockLike,
357 mut allow_calls: bool,
358 ) -> (CompletedMarker, BlockLike) {
360 lhs = match p.current() {
361 // test stmt_postfix_expr_ambiguity
369 T!['('] if allow_calls => call_expr(p, lhs),
370 T!['['] if allow_calls => index_expr(p, lhs),
371 T![.] => match postfix_dot_expr(p, lhs) {
378 T![?] => try_expr(p, lhs),
382 block_like = BlockLike::NotBlock;
384 return (lhs, block_like);
388 lhs: CompletedMarker,
389 ) -> Result<CompletedMarker, CompletedMarker> {
390 assert!(p.at(T![.]));
391 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
392 return Ok(method_call_expr(p, lhs));
399 // x.0().await?.hello();
401 if p.nth(1) == T![await] {
402 let m = lhs.precede(p);
405 return Ok(m.complete(p, AWAIT_EXPR));
408 if p.at(T![..=]) || p.at(T![..]) {
412 Ok(field_expr(p, lhs))
419 // let _ = f()(1)(1, 2,);
420 // let _ = f(<Foo>::func());
421 // f(<Foo as Trait>::func());
423 fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
424 assert!(p.at(T!['(']));
425 let m = lhs.precede(p);
427 m.complete(p, CALL_EXPR)
434 fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
435 assert!(p.at(T!['[']));
436 let m = lhs.precede(p);
440 m.complete(p, INDEX_EXPR)
443 // test method_call_expr
446 // y.bar::<T>(1, 2,);
448 fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
449 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
450 let m = lhs.precede(p);
453 generic_args::opt_generic_arg_list(p, true);
457 m.complete(p, METHOD_CALL_EXPR)
467 // test_err bad_tuple_index_expr
473 fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
474 assert!(p.at(T![.]));
475 let m = lhs.precede(p);
477 if p.at(IDENT) || p.at(INT_NUMBER) {
478 name_ref_or_index(p);
479 } else if p.at(FLOAT_NUMBER) {
480 // FIXME: How to recover and instead parse INT + T![.]?
483 p.error("expected field name or number");
485 m.complete(p, FIELD_EXPR)
492 fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
493 assert!(p.at(T![?]));
494 let m = lhs.precede(p);
496 m.complete(p, TRY_EXPR)
504 // 0x36 as u8 <= 0x37;
506 fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
507 assert!(p.at(T![as]));
508 let m = lhs.precede(p);
510 // Use type_no_bounds(), because cast expressions are not
511 // allowed to have bounds.
512 types::type_no_bounds(p);
513 m.complete(p, CAST_EXPR)
516 fn arg_list(p: &mut Parser) {
517 assert!(p.at(T!['(']));
520 while !p.at(T![')']) && !p.at(EOF) {
521 // test arg_with_attr
528 if !p.at(T![')']) && !p.expect(T![,]) {
533 m.complete(p, ARG_LIST);
541 // let _ = format!();
543 fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
544 assert!(paths::is_path_start(p));
548 T!['{'] if !r.forbid_structs => {
549 record_expr_field_list(p);
550 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
552 T![!] if !p.at(T![!=]) => {
553 let block_like = items::macro_call_after_excl(p);
554 (m.complete(p, MACRO_CALL), block_like)
556 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
564 // S { x, y: 32, ..Default::default() };
565 // TupleStruct { 0: 1 };
567 pub(crate) fn record_expr_field_list(p: &mut Parser) {
568 assert!(p.at(T!['{']));
571 while !p.at(EOF) && !p.at(T!['}']) {
573 // test record_literal_field_with_attr
575 // S { #[cfg(test)] field: 1 }
577 attributes::outer_attrs(p);
580 IDENT | INT_NUMBER => {
581 // test_err record_literal_before_ellipsis_recovery
583 // S { field ..S::default() }
585 if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
586 name_ref_or_index(p);
590 m.complete(p, RECORD_EXPR_FIELD);
592 T![.] if p.at(T![..]) => {
598 error_block(p, "expected a field");
602 p.err_and_bump("expected identifier");
611 m.complete(p, RECORD_EXPR_FIELD_LIST);