diff options
Diffstat (limited to 'crates/parser/src/grammar/expressions.rs')
-rw-r--r-- | crates/parser/src/grammar/expressions.rs | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs new file mode 100644 index 000000000..e72929f8c --- /dev/null +++ b/crates/parser/src/grammar/expressions.rs | |||
@@ -0,0 +1,651 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | mod atom; | ||
4 | |||
5 | pub(crate) use self::atom::{block_expr, match_arm_list}; | ||
6 | pub(super) use self::atom::{literal, LITERAL_FIRST}; | ||
7 | use super::*; | ||
8 | |||
9 | pub(super) enum StmtWithSemi { | ||
10 | Yes, | ||
11 | No, | ||
12 | Optional, | ||
13 | } | ||
14 | |||
15 | const EXPR_FIRST: TokenSet = LHS_FIRST; | ||
16 | |||
17 | pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { | ||
18 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; | ||
19 | expr_bp(p, r, 1) | ||
20 | } | ||
21 | |||
22 | pub(super) fn expr_with_attrs(p: &mut Parser) -> bool { | ||
23 | let m = p.start(); | ||
24 | let has_attrs = p.at(T![#]); | ||
25 | attributes::outer_attrs(p); | ||
26 | |||
27 | let (cm, _block_like) = expr(p); | ||
28 | let success = cm.is_some(); | ||
29 | |||
30 | match (has_attrs, cm) { | ||
31 | (true, Some(cm)) => { | ||
32 | let kind = cm.kind(); | ||
33 | cm.undo_completion(p).abandon(p); | ||
34 | m.complete(p, kind); | ||
35 | } | ||
36 | _ => m.abandon(p), | ||
37 | } | ||
38 | |||
39 | success | ||
40 | } | ||
41 | |||
42 | pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { | ||
43 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; | ||
44 | expr_bp(p, r, 1) | ||
45 | } | ||
46 | |||
47 | fn expr_no_struct(p: &mut Parser) { | ||
48 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; | ||
49 | expr_bp(p, r, 1); | ||
50 | } | ||
51 | |||
52 | fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { | ||
53 | let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR); | ||
54 | !forbid | ||
55 | } | ||
56 | |||
57 | pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { | ||
58 | let m = p.start(); | ||
59 | // test attr_on_expr_stmt | ||
60 | // fn foo() { | ||
61 | // #[A] foo(); | ||
62 | // #[B] bar!{} | ||
63 | // #[C] #[D] {} | ||
64 | // #[D] return (); | ||
65 | // } | ||
66 | let has_attrs = p.at(T![#]); | ||
67 | attributes::outer_attrs(p); | ||
68 | |||
69 | if p.at(T![let]) { | ||
70 | let_stmt(p, m, with_semi); | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | // test block_items | ||
75 | // fn a() { fn b() {} } | ||
76 | let m = match items::maybe_item(p, m) { | ||
77 | Ok(()) => return, | ||
78 | Err(m) => m, | ||
79 | }; | ||
80 | |||
81 | let (cm, blocklike) = expr_stmt(p); | ||
82 | let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR); | ||
83 | |||
84 | if has_attrs && !is_expr_stmt_attr_allowed(kind) { | ||
85 | // test_err attr_on_expr_not_allowed | ||
86 | // fn foo() { | ||
87 | // #[A] 1 + 2; | ||
88 | // #[B] if true {}; | ||
89 | // } | ||
90 | p.error(format!("attributes are not allowed on {:?}", kind)); | ||
91 | } | ||
92 | |||
93 | if p.at(T!['}']) { | ||
94 | // test attr_on_last_expr_in_block | ||
95 | // fn foo() { | ||
96 | // { #[A] bar!()? } | ||
97 | // #[B] &() | ||
98 | // } | ||
99 | if let Some(cm) = cm { | ||
100 | cm.undo_completion(p).abandon(p); | ||
101 | m.complete(p, kind); | ||
102 | } else { | ||
103 | m.abandon(p); | ||
104 | } | ||
105 | } else { | ||
106 | // test no_semi_after_block | ||
107 | // fn foo() { | ||
108 | // if true {} | ||
109 | // loop {} | ||
110 | // match () {} | ||
111 | // while true {} | ||
112 | // for _ in () {} | ||
113 | // {} | ||
114 | // {} | ||
115 | // macro_rules! test { | ||
116 | // () => {} | ||
117 | // } | ||
118 | // test!{} | ||
119 | // } | ||
120 | |||
121 | match with_semi { | ||
122 | StmtWithSemi::Yes => { | ||
123 | if blocklike.is_block() { | ||
124 | p.eat(T![;]); | ||
125 | } else { | ||
126 | p.expect(T![;]); | ||
127 | } | ||
128 | } | ||
129 | StmtWithSemi::No => {} | ||
130 | StmtWithSemi::Optional => { | ||
131 | if p.at(T![;]) { | ||
132 | p.eat(T![;]); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | m.complete(p, EXPR_STMT); | ||
138 | } | ||
139 | |||
140 | // test let_stmt | ||
141 | // fn foo() { | ||
142 | // let a; | ||
143 | // let b: i32; | ||
144 | // let c = 92; | ||
145 | // let d: i32 = 92; | ||
146 | // let e: !; | ||
147 | // let _: ! = {}; | ||
148 | // let f = #[attr]||{}; | ||
149 | // } | ||
150 | fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) { | ||
151 | assert!(p.at(T![let])); | ||
152 | p.bump(T![let]); | ||
153 | patterns::pattern(p); | ||
154 | if p.at(T![:]) { | ||
155 | types::ascription(p); | ||
156 | } | ||
157 | if p.eat(T![=]) { | ||
158 | expressions::expr_with_attrs(p); | ||
159 | } | ||
160 | |||
161 | match with_semi { | ||
162 | StmtWithSemi::Yes => { | ||
163 | p.expect(T![;]); | ||
164 | } | ||
165 | StmtWithSemi::No => {} | ||
166 | StmtWithSemi::Optional => { | ||
167 | if p.at(T![;]) { | ||
168 | p.eat(T![;]); | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | m.complete(p, LET_STMT); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | pub(super) fn expr_block_contents(p: &mut Parser) { | ||
177 | // This is checked by a validator | ||
178 | attributes::inner_attrs(p); | ||
179 | |||
180 | while !p.at(EOF) && !p.at(T!['}']) { | ||
181 | // test nocontentexpr | ||
182 | // fn foo(){ | ||
183 | // ;;;some_expr();;;;{;;;};;;;Ok(()) | ||
184 | // } | ||
185 | |||
186 | // test nocontentexpr_after_item | ||
187 | // fn simple_function() { | ||
188 | // enum LocalEnum { | ||
189 | // One, | ||
190 | // Two, | ||
191 | // }; | ||
192 | // fn f() {}; | ||
193 | // struct S {}; | ||
194 | // } | ||
195 | |||
196 | if p.at(T![;]) { | ||
197 | p.bump(T![;]); | ||
198 | continue; | ||
199 | } | ||
200 | |||
201 | stmt(p, StmtWithSemi::Yes) | ||
202 | } | ||
203 | } | ||
204 | |||
205 | #[derive(Clone, Copy)] | ||
206 | struct Restrictions { | ||
207 | forbid_structs: bool, | ||
208 | prefer_stmt: bool, | ||
209 | } | ||
210 | |||
211 | /// Binding powers of operators for a Pratt parser. | ||
212 | /// | ||
213 | /// See https://www.oilshell.org/blog/2016/11/03.html | ||
214 | #[rustfmt::skip] | ||
215 | fn current_op(p: &Parser) -> (u8, SyntaxKind) { | ||
216 | const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]); | ||
217 | match p.current() { | ||
218 | T![|] if p.at(T![||]) => (3, T![||]), | ||
219 | T![|] if p.at(T![|=]) => (1, T![|=]), | ||
220 | T![|] => (6, T![|]), | ||
221 | T![>] if p.at(T![>>=]) => (1, T![>>=]), | ||
222 | T![>] if p.at(T![>>]) => (9, T![>>]), | ||
223 | T![>] if p.at(T![>=]) => (5, T![>=]), | ||
224 | T![>] => (5, T![>]), | ||
225 | T![=] if p.at(T![=>]) => NOT_AN_OP, | ||
226 | T![=] if p.at(T![==]) => (5, T![==]), | ||
227 | T![=] => (1, T![=]), | ||
228 | T![<] if p.at(T![<=]) => (5, T![<=]), | ||
229 | T![<] if p.at(T![<<=]) => (1, T![<<=]), | ||
230 | T![<] if p.at(T![<<]) => (9, T![<<]), | ||
231 | T![<] => (5, T![<]), | ||
232 | T![+] if p.at(T![+=]) => (1, T![+=]), | ||
233 | T![+] => (10, T![+]), | ||
234 | T![^] if p.at(T![^=]) => (1, T![^=]), | ||
235 | T![^] => (7, T![^]), | ||
236 | T![%] if p.at(T![%=]) => (1, T![%=]), | ||
237 | T![%] => (11, T![%]), | ||
238 | T![&] if p.at(T![&=]) => (1, T![&=]), | ||
239 | T![&] if p.at(T![&&]) => (4, T![&&]), | ||
240 | T![&] => (8, T![&]), | ||
241 | T![/] if p.at(T![/=]) => (1, T![/=]), | ||
242 | T![/] => (11, T![/]), | ||
243 | T![*] if p.at(T![*=]) => (1, T![*=]), | ||
244 | T![*] => (11, T![*]), | ||
245 | T![.] if p.at(T![..=]) => (2, T![..=]), | ||
246 | T![.] if p.at(T![..]) => (2, T![..]), | ||
247 | T![!] if p.at(T![!=]) => (5, T![!=]), | ||
248 | T![-] if p.at(T![-=]) => (1, T![-=]), | ||
249 | T![-] => (10, T![-]), | ||
250 | T![as] => (12, T![as]), | ||
251 | |||
252 | _ => NOT_AN_OP | ||
253 | } | ||
254 | } | ||
255 | |||
256 | // Parses expression with binding power of at least bp. | ||
257 | fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) { | ||
258 | let mut lhs = match lhs(p, r) { | ||
259 | Some((lhs, blocklike)) => { | ||
260 | // test stmt_bin_expr_ambiguity | ||
261 | // fn foo() { | ||
262 | // let _ = {1} & 2; | ||
263 | // {1} &2; | ||
264 | // } | ||
265 | if r.prefer_stmt && blocklike.is_block() { | ||
266 | return (Some(lhs), BlockLike::Block); | ||
267 | } | ||
268 | lhs | ||
269 | } | ||
270 | None => return (None, BlockLike::NotBlock), | ||
271 | }; | ||
272 | |||
273 | loop { | ||
274 | let is_range = p.at(T![..]) || p.at(T![..=]); | ||
275 | let (op_bp, op) = current_op(p); | ||
276 | if op_bp < bp { | ||
277 | break; | ||
278 | } | ||
279 | // test as_precedence | ||
280 | // fn foo() { | ||
281 | // let _ = &1 as *const i32; | ||
282 | // } | ||
283 | if p.at(T![as]) { | ||
284 | lhs = cast_expr(p, lhs); | ||
285 | continue; | ||
286 | } | ||
287 | let m = lhs.precede(p); | ||
288 | p.bump(op); | ||
289 | |||
290 | // test binop_resets_statementness | ||
291 | // fn foo() { | ||
292 | // v = {1}&2; | ||
293 | // } | ||
294 | r = Restrictions { prefer_stmt: false, ..r }; | ||
295 | |||
296 | if is_range { | ||
297 | // test postfix_range | ||
298 | // fn foo() { | ||
299 | // let x = 1..; | ||
300 | // match 1.. { _ => () }; | ||
301 | // match a.b()..S { _ => () }; | ||
302 | // } | ||
303 | let has_trailing_expression = | ||
304 | p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])); | ||
305 | if !has_trailing_expression { | ||
306 | // no RHS | ||
307 | lhs = m.complete(p, RANGE_EXPR); | ||
308 | break; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1); | ||
313 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | ||
314 | } | ||
315 | (Some(lhs), BlockLike::NotBlock) | ||
316 | } | ||
317 | |||
318 | const LHS_FIRST: TokenSet = | ||
319 | atom::ATOM_EXPR_FIRST.union(token_set![T![&], T![*], T![!], T![.], T![-]]); | ||
320 | |||
321 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { | ||
322 | let m; | ||
323 | let kind = match p.current() { | ||
324 | // test ref_expr | ||
325 | // fn foo() { | ||
326 | // // reference operator | ||
327 | // let _ = &1; | ||
328 | // let _ = &mut &f(); | ||
329 | // let _ = &raw; | ||
330 | // let _ = &raw.0; | ||
331 | // // raw reference operator | ||
332 | // let _ = &raw mut foo; | ||
333 | // let _ = &raw const foo; | ||
334 | // } | ||
335 | T![&] => { | ||
336 | m = p.start(); | ||
337 | p.bump(T![&]); | ||
338 | if p.at(IDENT) | ||
339 | && p.at_contextual_kw("raw") | ||
340 | && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) | ||
341 | { | ||
342 | p.bump_remap(T![raw]); | ||
343 | p.bump_any(); | ||
344 | } else { | ||
345 | p.eat(T![mut]); | ||
346 | } | ||
347 | REF_EXPR | ||
348 | } | ||
349 | // test unary_expr | ||
350 | // fn foo() { | ||
351 | // **&1; | ||
352 | // !!true; | ||
353 | // --1; | ||
354 | // } | ||
355 | T![*] | T![!] | T![-] => { | ||
356 | m = p.start(); | ||
357 | p.bump_any(); | ||
358 | PREFIX_EXPR | ||
359 | } | ||
360 | _ => { | ||
361 | // test full_range_expr | ||
362 | // fn foo() { xs[..]; } | ||
363 | for &op in [T![..=], T![..]].iter() { | ||
364 | if p.at(op) { | ||
365 | m = p.start(); | ||
366 | p.bump(op); | ||
367 | if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) { | ||
368 | expr_bp(p, r, 2); | ||
369 | } | ||
370 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | // test expression_after_block | ||
375 | // fn foo() { | ||
376 | // let mut p = F{x: 5}; | ||
377 | // {p}.x = 10; | ||
378 | // } | ||
379 | // | ||
380 | let (lhs, blocklike) = atom::atom_expr(p, r)?; | ||
381 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); | ||
382 | } | ||
383 | }; | ||
384 | // parse the interior of the unary expression | ||
385 | expr_bp(p, r, 255); | ||
386 | Some((m.complete(p, kind), BlockLike::NotBlock)) | ||
387 | } | ||
388 | |||
389 | fn postfix_expr( | ||
390 | p: &mut Parser, | ||
391 | mut lhs: CompletedMarker, | ||
392 | // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple | ||
393 | // E.g. `while true {break}();` is parsed as | ||
394 | // `while true {break}; ();` | ||
395 | mut block_like: BlockLike, | ||
396 | mut allow_calls: bool, | ||
397 | ) -> (CompletedMarker, BlockLike) { | ||
398 | loop { | ||
399 | lhs = match p.current() { | ||
400 | // test stmt_postfix_expr_ambiguity | ||
401 | // fn foo() { | ||
402 | // match () { | ||
403 | // _ => {} | ||
404 | // () => {} | ||
405 | // [] => {} | ||
406 | // } | ||
407 | // } | ||
408 | T!['('] if allow_calls => call_expr(p, lhs), | ||
409 | T!['['] if allow_calls => index_expr(p, lhs), | ||
410 | T![.] => match postfix_dot_expr(p, lhs) { | ||
411 | Ok(it) => it, | ||
412 | Err(it) => { | ||
413 | lhs = it; | ||
414 | break; | ||
415 | } | ||
416 | }, | ||
417 | T![?] => try_expr(p, lhs), | ||
418 | _ => break, | ||
419 | }; | ||
420 | allow_calls = true; | ||
421 | block_like = BlockLike::NotBlock; | ||
422 | } | ||
423 | return (lhs, block_like); | ||
424 | |||
425 | fn postfix_dot_expr( | ||
426 | p: &mut Parser, | ||
427 | lhs: CompletedMarker, | ||
428 | ) -> Result<CompletedMarker, CompletedMarker> { | ||
429 | assert!(p.at(T![.])); | ||
430 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { | ||
431 | return Ok(method_call_expr(p, lhs)); | ||
432 | } | ||
433 | |||
434 | // test await_expr | ||
435 | // fn foo() { | ||
436 | // x.await; | ||
437 | // x.0.await; | ||
438 | // x.0().await?.hello(); | ||
439 | // } | ||
440 | if p.nth(1) == T![await] { | ||
441 | let m = lhs.precede(p); | ||
442 | p.bump(T![.]); | ||
443 | p.bump(T![await]); | ||
444 | return Ok(m.complete(p, AWAIT_EXPR)); | ||
445 | } | ||
446 | |||
447 | if p.at(T![..=]) || p.at(T![..]) { | ||
448 | return Err(lhs); | ||
449 | } | ||
450 | |||
451 | Ok(field_expr(p, lhs)) | ||
452 | } | ||
453 | } | ||
454 | |||
455 | // test call_expr | ||
456 | // fn foo() { | ||
457 | // let _ = f(); | ||
458 | // let _ = f()(1)(1, 2,); | ||
459 | // let _ = f(<Foo>::func()); | ||
460 | // f(<Foo as Trait>::func()); | ||
461 | // } | ||
462 | fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
463 | assert!(p.at(T!['('])); | ||
464 | let m = lhs.precede(p); | ||
465 | arg_list(p); | ||
466 | m.complete(p, CALL_EXPR) | ||
467 | } | ||
468 | |||
469 | // test index_expr | ||
470 | // fn foo() { | ||
471 | // x[1][2]; | ||
472 | // } | ||
473 | fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
474 | assert!(p.at(T!['['])); | ||
475 | let m = lhs.precede(p); | ||
476 | p.bump(T!['[']); | ||
477 | expr(p); | ||
478 | p.expect(T![']']); | ||
479 | m.complete(p, INDEX_EXPR) | ||
480 | } | ||
481 | |||
482 | // test method_call_expr | ||
483 | // fn foo() { | ||
484 | // x.foo(); | ||
485 | // y.bar::<T>(1, 2,); | ||
486 | // } | ||
487 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
488 | assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); | ||
489 | let m = lhs.precede(p); | ||
490 | p.bump_any(); | ||
491 | name_ref(p); | ||
492 | type_args::opt_generic_arg_list(p, true); | ||
493 | if p.at(T!['(']) { | ||
494 | arg_list(p); | ||
495 | } | ||
496 | m.complete(p, METHOD_CALL_EXPR) | ||
497 | } | ||
498 | |||
499 | // test field_expr | ||
500 | // fn foo() { | ||
501 | // x.foo; | ||
502 | // x.0.bar; | ||
503 | // x.0(); | ||
504 | // } | ||
505 | |||
506 | // test_err bad_tuple_index_expr | ||
507 | // fn foo() { | ||
508 | // x.0.; | ||
509 | // x.1i32; | ||
510 | // x.0x01; | ||
511 | // } | ||
512 | fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
513 | assert!(p.at(T![.])); | ||
514 | let m = lhs.precede(p); | ||
515 | p.bump(T![.]); | ||
516 | if p.at(IDENT) || p.at(INT_NUMBER) { | ||
517 | name_ref_or_index(p) | ||
518 | } else if p.at(FLOAT_NUMBER) { | ||
519 | // FIXME: How to recover and instead parse INT + T![.]? | ||
520 | p.bump_any(); | ||
521 | } else { | ||
522 | p.error("expected field name or number") | ||
523 | } | ||
524 | m.complete(p, FIELD_EXPR) | ||
525 | } | ||
526 | |||
527 | // test try_expr | ||
528 | // fn foo() { | ||
529 | // x?; | ||
530 | // } | ||
531 | fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
532 | assert!(p.at(T![?])); | ||
533 | let m = lhs.precede(p); | ||
534 | p.bump(T![?]); | ||
535 | m.complete(p, TRY_EXPR) | ||
536 | } | ||
537 | |||
538 | // test cast_expr | ||
539 | // fn foo() { | ||
540 | // 82 as i32; | ||
541 | // 81 as i8 + 1; | ||
542 | // 79 as i16 - 1; | ||
543 | // 0x36 as u8 <= 0x37; | ||
544 | // } | ||
545 | fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
546 | assert!(p.at(T![as])); | ||
547 | let m = lhs.precede(p); | ||
548 | p.bump(T![as]); | ||
549 | // Use type_no_bounds(), because cast expressions are not | ||
550 | // allowed to have bounds. | ||
551 | types::type_no_bounds(p); | ||
552 | m.complete(p, CAST_EXPR) | ||
553 | } | ||
554 | |||
555 | fn arg_list(p: &mut Parser) { | ||
556 | assert!(p.at(T!['('])); | ||
557 | let m = p.start(); | ||
558 | p.bump(T!['(']); | ||
559 | while !p.at(T![')']) && !p.at(EOF) { | ||
560 | // test arg_with_attr | ||
561 | // fn main() { | ||
562 | // foo(#[attr] 92) | ||
563 | // } | ||
564 | if !expr_with_attrs(p) { | ||
565 | break; | ||
566 | } | ||
567 | if !p.at(T![')']) && !p.expect(T![,]) { | ||
568 | break; | ||
569 | } | ||
570 | } | ||
571 | p.eat(T![')']); | ||
572 | m.complete(p, ARG_LIST); | ||
573 | } | ||
574 | |||
575 | // test path_expr | ||
576 | // fn foo() { | ||
577 | // let _ = a; | ||
578 | // let _ = a::b; | ||
579 | // let _ = ::a::<b>; | ||
580 | // let _ = format!(); | ||
581 | // } | ||
582 | fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { | ||
583 | assert!(paths::is_path_start(p)); | ||
584 | let m = p.start(); | ||
585 | paths::expr_path(p); | ||
586 | match p.current() { | ||
587 | T!['{'] if !r.forbid_structs => { | ||
588 | record_expr_field_list(p); | ||
589 | (m.complete(p, RECORD_EXPR), BlockLike::NotBlock) | ||
590 | } | ||
591 | T![!] if !p.at(T![!=]) => { | ||
592 | let block_like = items::macro_call_after_excl(p); | ||
593 | (m.complete(p, MACRO_CALL), block_like) | ||
594 | } | ||
595 | _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock), | ||
596 | } | ||
597 | } | ||
598 | |||
599 | // test record_lit | ||
600 | // fn foo() { | ||
601 | // S {}; | ||
602 | // S { x, y: 32, }; | ||
603 | // S { x, y: 32, ..Default::default() }; | ||
604 | // TupleStruct { 0: 1 }; | ||
605 | // } | ||
606 | pub(crate) fn record_expr_field_list(p: &mut Parser) { | ||
607 | assert!(p.at(T!['{'])); | ||
608 | let m = p.start(); | ||
609 | p.bump(T!['{']); | ||
610 | while !p.at(EOF) && !p.at(T!['}']) { | ||
611 | let m = p.start(); | ||
612 | // test record_literal_field_with_attr | ||
613 | // fn main() { | ||
614 | // S { #[cfg(test)] field: 1 } | ||
615 | // } | ||
616 | attributes::outer_attrs(p); | ||
617 | |||
618 | match p.current() { | ||
619 | IDENT | INT_NUMBER => { | ||
620 | // test_err record_literal_before_ellipsis_recovery | ||
621 | // fn main() { | ||
622 | // S { field ..S::default() } | ||
623 | // } | ||
624 | if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { | ||
625 | name_ref_or_index(p); | ||
626 | p.expect(T![:]); | ||
627 | } | ||
628 | expr(p); | ||
629 | m.complete(p, RECORD_EXPR_FIELD); | ||
630 | } | ||
631 | T![.] if p.at(T![..]) => { | ||
632 | m.abandon(p); | ||
633 | p.bump(T![..]); | ||
634 | expr(p); | ||
635 | } | ||
636 | T!['{'] => { | ||
637 | error_block(p, "expected a field"); | ||
638 | m.abandon(p); | ||
639 | } | ||
640 | _ => { | ||
641 | p.err_and_bump("expected identifier"); | ||
642 | m.abandon(p); | ||
643 | } | ||
644 | } | ||
645 | if !p.at(T!['}']) { | ||
646 | p.expect(T![,]); | ||
647 | } | ||
648 | } | ||
649 | p.expect(T!['}']); | ||
650 | m.complete(p, RECORD_EXPR_FIELD_LIST); | ||
651 | } | ||