aboutsummaryrefslogtreecommitdiff
path: root/crates/libsyntax2/src/grammar/expressions
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libsyntax2/src/grammar/expressions')
-rw-r--r--crates/libsyntax2/src/grammar/expressions/atom.rs400
-rw-r--r--crates/libsyntax2/src/grammar/expressions/mod.rs450
2 files changed, 0 insertions, 850 deletions
diff --git a/crates/libsyntax2/src/grammar/expressions/atom.rs b/crates/libsyntax2/src/grammar/expressions/atom.rs
deleted file mode 100644
index f01df56bc..000000000
--- a/crates/libsyntax2/src/grammar/expressions/atom.rs
+++ /dev/null
@@ -1,400 +0,0 @@
1use super::*;
2
3// test expr_literals
4// fn foo() {
5// let _ = true;
6// let _ = false;
7// let _ = 1;
8// let _ = 2.0;
9// let _ = b'a';
10// let _ = 'b';
11// let _ = "c";
12// let _ = r"d";
13// let _ = b"e";
14// let _ = br"f";
15// }
16pub(crate) const LITERAL_FIRST: TokenSet =
17 token_set![TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR,
18 STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
19
20pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
21 if !p.at_ts(LITERAL_FIRST) {
22 return None;
23 }
24 let m = p.start();
25 p.bump();
26 Some(m.complete(p, LITERAL))
27}
28
29pub(super) const ATOM_EXPR_FIRST: TokenSet =
30 token_set_union![
31 LITERAL_FIRST,
32 token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW,
33 RETURN_KW, IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
34 ];
35
36const EXPR_RECOVERY_SET: TokenSet =
37 token_set![LET_KW];
38
39pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
40 match literal(p) {
41 Some(m) => return Some(m),
42 None => (),
43 }
44 if paths::is_path_start(p) || p.at(L_ANGLE) {
45 return Some(path_expr(p, r));
46 }
47 let la = p.nth(1);
48 let done = match p.current() {
49 L_PAREN => tuple_expr(p),
50 L_BRACK => array_expr(p),
51 PIPE => lambda_expr(p),
52 MOVE_KW if la == PIPE => lambda_expr(p),
53 IF_KW => if_expr(p),
54
55 LOOP_KW => loop_expr(p, None),
56 FOR_KW => for_expr(p, None),
57 WHILE_KW => while_expr(p, None),
58 LIFETIME if la == COLON => {
59 let m = p.start();
60 label(p);
61 match p.current() {
62 LOOP_KW => loop_expr(p, Some(m)),
63 FOR_KW => for_expr(p, Some(m)),
64 WHILE_KW => while_expr(p, Some(m)),
65 L_CURLY => block_expr(p, Some(m)),
66 _ => {
67 // test misplaced_label_err
68 // fn main() {
69 // 'loop: impl
70 // }
71 p.error("expected a loop");
72 m.complete(p, ERROR);
73 return None;
74 }
75 }
76 }
77
78 MATCH_KW => match_expr(p),
79 UNSAFE_KW if la == L_CURLY => {
80 let m = p.start();
81 p.bump();
82 block_expr(p, Some(m))
83 },
84 L_CURLY => block_expr(p, None),
85 RETURN_KW => return_expr(p),
86 CONTINUE_KW => continue_expr(p),
87 BREAK_KW => break_expr(p),
88 _ => {
89 p.err_recover("expected expression", EXPR_RECOVERY_SET);
90 return None;
91 }
92 };
93 Some(done)
94}
95
96// test tuple_expr
97// fn foo() {
98// ();
99// (1);
100// (1,);
101// }
102fn tuple_expr(p: &mut Parser) -> CompletedMarker {
103 assert!(p.at(L_PAREN));
104 let m = p.start();
105 p.expect(L_PAREN);
106
107 let mut saw_comma = false;
108 let mut saw_expr = false;
109 while !p.at(EOF) && !p.at(R_PAREN) {
110 saw_expr = true;
111 if !p.at_ts(EXPR_FIRST) {
112 p.error("expected expression");
113 break;
114 }
115 expr(p);
116 if !p.at(R_PAREN) {
117 saw_comma = true;
118 p.expect(COMMA);
119 }
120 }
121 p.expect(R_PAREN);
122 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
123}
124
125// test array_expr
126// fn foo() {
127// [];
128// [1];
129// [1, 2,];
130// [1; 2];
131// }
132fn array_expr(p: &mut Parser) -> CompletedMarker {
133 assert!(p.at(L_BRACK));
134 let m = p.start();
135 p.bump();
136 if p.eat(R_BRACK) {
137 return m.complete(p, ARRAY_EXPR);
138 }
139 expr(p);
140 if p.eat(SEMI) {
141 expr(p);
142 p.expect(R_BRACK);
143 return m.complete(p, ARRAY_EXPR);
144 }
145 while !p.at(EOF) && !p.at(R_BRACK) {
146 p.expect(COMMA);
147 if p.at(R_BRACK) {
148 break;
149 }
150 if !p.at_ts(EXPR_FIRST) {
151 p.error("expected expression");
152 break;
153 }
154 expr(p);
155 }
156 p.expect(R_BRACK);
157 m.complete(p, ARRAY_EXPR)
158}
159
160// test lambda_expr
161// fn foo() {
162// || ();
163// || -> i32 { 92 };
164// |x| x;
165// move |x: i32,| x;
166// }
167fn lambda_expr(p: &mut Parser) -> CompletedMarker {
168 assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
169 let m = p.start();
170 p.eat(MOVE_KW);
171 params::param_list_opt_types(p);
172 if opt_fn_ret_type(p) {
173 if !p.at(L_CURLY) {
174 p.error("expected `{`");
175 }
176 }
177 expr(p);
178 m.complete(p, LAMBDA_EXPR)
179}
180
181// test if_expr
182// fn foo() {
183// if true {};
184// if true {} else {};
185// if true {} else if false {} else {};
186// if S {};
187// }
188fn if_expr(p: &mut Parser) -> CompletedMarker {
189 assert!(p.at(IF_KW));
190 let m = p.start();
191 p.bump();
192 cond(p);
193 block(p);
194 if p.at(ELSE_KW) {
195 p.bump();
196 if p.at(IF_KW) {
197 if_expr(p);
198 } else {
199 block(p);
200 }
201 }
202 m.complete(p, IF_EXPR)
203}
204
205// test label
206// fn foo() {
207// 'a: loop {}
208// 'b: while true {}
209// 'c: for x in () {}
210// }
211fn label(p: &mut Parser) {
212 assert!(p.at(LIFETIME) && p.nth(1) == COLON);
213 let m = p.start();
214 p.bump();
215 p.bump();
216 m.complete(p, LABEL);
217}
218
219// test loop_expr
220// fn foo() {
221// loop {};
222// }
223fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
224 assert!(p.at(LOOP_KW));
225 let m = m.unwrap_or_else(|| p.start());
226 p.bump();
227 block(p);
228 m.complete(p, LOOP_EXPR)
229}
230
231// test while_expr
232// fn foo() {
233// while true {};
234// while let Some(x) = it.next() {};
235// }
236fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
237 assert!(p.at(WHILE_KW));
238 let m = m.unwrap_or_else(|| p.start());
239 p.bump();
240 cond(p);
241 block(p);
242 m.complete(p, WHILE_EXPR)
243}
244
245// test for_expr
246// fn foo() {
247// for x in [] {};
248// }
249fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
250 assert!(p.at(FOR_KW));
251 let m = m.unwrap_or_else(|| p.start());
252 p.bump();
253 patterns::pattern(p);
254 p.expect(IN_KW);
255 expr_no_struct(p);
256 block(p);
257 m.complete(p, FOR_EXPR)
258}
259
260// test cond
261// fn foo() { if let Some(_) = None {} }
262fn cond(p: &mut Parser) {
263 let m = p.start();
264 if p.eat(LET_KW) {
265 patterns::pattern(p);
266 p.expect(EQ);
267 }
268 expr_no_struct(p);
269 m.complete(p, CONDITION);
270}
271
272// test match_expr
273// fn foo() {
274// match () { };
275// match S {};
276// }
277fn match_expr(p: &mut Parser) -> CompletedMarker {
278 assert!(p.at(MATCH_KW));
279 let m = p.start();
280 p.bump();
281 expr_no_struct(p);
282 if p.at(L_CURLY) {
283 match_arm_list(p);
284 } else {
285 p.error("expected `{`")
286 }
287 m.complete(p, MATCH_EXPR)
288}
289
290pub(crate) fn match_arm_list(p: &mut Parser) {
291 assert!(p.at(L_CURLY));
292 let m = p.start();
293 p.eat(L_CURLY);
294 while !p.at(EOF) && !p.at(R_CURLY) {
295 if p.at(L_CURLY) {
296 error_block(p, "expected match arm");
297 continue;
298 }
299 // test match_arms_commas
300 // fn foo() {
301 // match () {
302 // _ => (),
303 // _ => {}
304 // _ => ()
305 // }
306 // }
307 if match_arm(p).is_block() {
308 p.eat(COMMA);
309 } else if !p.at(R_CURLY) {
310 p.expect(COMMA);
311 }
312 }
313 p.expect(R_CURLY);
314 m.complete(p, MATCH_ARM_LIST);
315}
316
317// test match_arm
318// fn foo() {
319// match () {
320// _ => (),
321// X | Y if Z => (),
322// };
323// }
324fn match_arm(p: &mut Parser) -> BlockLike {
325 let m = p.start();
326 patterns::pattern_r(p, TokenSet::EMPTY);
327 while p.eat(PIPE) {
328 patterns::pattern(p);
329 }
330 if p.eat(IF_KW) {
331 expr_no_struct(p);
332 }
333 p.expect(FAT_ARROW);
334 let ret = expr_stmt(p);
335 m.complete(p, MATCH_ARM);
336 ret
337}
338
339// test block_expr
340// fn foo() {
341// {};
342// unsafe {};
343// 'label: {};
344// }
345fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
346 assert!(p.at(L_CURLY));
347 let m = m.unwrap_or_else(|| p.start());
348 block(p);
349 m.complete(p, BLOCK_EXPR)
350}
351
352// test return_expr
353// fn foo() {
354// return;
355// return 92;
356// }
357fn return_expr(p: &mut Parser) -> CompletedMarker {
358 assert!(p.at(RETURN_KW));
359 let m = p.start();
360 p.bump();
361 if p.at_ts(EXPR_FIRST) {
362 expr(p);
363 }
364 m.complete(p, RETURN_EXPR)
365}
366
367// test continue_expr
368// fn foo() {
369// loop {
370// continue;
371// continue 'l;
372// }
373// }
374fn continue_expr(p: &mut Parser) -> CompletedMarker {
375 assert!(p.at(CONTINUE_KW));
376 let m = p.start();
377 p.bump();
378 p.eat(LIFETIME);
379 m.complete(p, CONTINUE_EXPR)
380}
381
382// test break_expr
383// fn foo() {
384// loop {
385// break;
386// break 'l;
387// break 92;
388// break 'l 92;
389// }
390// }
391fn break_expr(p: &mut Parser) -> CompletedMarker {
392 assert!(p.at(BREAK_KW));
393 let m = p.start();
394 p.bump();
395 p.eat(LIFETIME);
396 if p.at_ts(EXPR_FIRST) {
397 expr(p);
398 }
399 m.complete(p, BREAK_EXPR)
400}
diff --git a/crates/libsyntax2/src/grammar/expressions/mod.rs b/crates/libsyntax2/src/grammar/expressions/mod.rs
deleted file mode 100644
index 20e0fa328..000000000
--- a/crates/libsyntax2/src/grammar/expressions/mod.rs
+++ /dev/null
@@ -1,450 +0,0 @@
1mod atom;
2
3use super::*;
4pub(super) use self::atom::{literal, LITERAL_FIRST};
5pub(crate) use self::atom::match_arm_list;
6
7const EXPR_FIRST: TokenSet = LHS_FIRST;
8
9pub(super) fn expr(p: &mut Parser) -> BlockLike {
10 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
11 expr_bp(p, r, 1)
12}
13
14pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
15 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
16 expr_bp(p, r, 1)
17}
18
19fn expr_no_struct(p: &mut Parser) {
20 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
21 expr_bp(p, r, 1);
22}
23
24// test block
25// fn a() {}
26// fn b() { let _ = 1; }
27// fn c() { 1; 2; }
28// fn d() { 1; 2 }
29pub(crate) fn block(p: &mut Parser) {
30 if !p.at(L_CURLY) {
31 p.error("expected a block");
32 return;
33 }
34 let m = p.start();
35 p.bump();
36 while !p.at(EOF) && !p.at(R_CURLY) {
37 match p.current() {
38 LET_KW => let_stmt(p),
39 _ => {
40 // test block_items
41 // fn a() { fn b() {} }
42 let m = p.start();
43 match items::maybe_item(p, items::ItemFlavor::Mod) {
44 items::MaybeItem::Item(kind) => {
45 m.complete(p, kind);
46 }
47 items::MaybeItem::Modifiers => {
48 m.abandon(p);
49 p.error("expected an item");
50 }
51 // test pub_expr
52 // fn foo() { pub 92; } //FIXME
53 items::MaybeItem::None => {
54 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
55 if p.at(R_CURLY) {
56 m.abandon(p);
57 } else {
58 if is_blocklike {
59 p.eat(SEMI);
60 } else {
61 p.expect(SEMI);
62 }
63 m.complete(p, EXPR_STMT);
64 }
65 }
66 }
67 }
68 }
69 }
70 p.expect(R_CURLY);
71 m.complete(p, BLOCK);
72
73 // test let_stmt;
74 // fn foo() {
75 // let a;
76 // let b: i32;
77 // let c = 92;
78 // let d: i32 = 92;
79 // }
80 fn let_stmt(p: &mut Parser) {
81 assert!(p.at(LET_KW));
82 let m = p.start();
83 p.bump();
84 patterns::pattern(p);
85 if p.at(COLON) {
86 types::ascription(p);
87 }
88 if p.eat(EQ) {
89 expressions::expr(p);
90 }
91 p.expect(SEMI);
92 m.complete(p, LET_STMT);
93 }
94}
95
96#[derive(Clone, Copy)]
97struct Restrictions {
98 forbid_structs: bool,
99 prefer_stmt: bool,
100}
101
102enum Op {
103 Simple,
104 Composite(SyntaxKind, u8),
105}
106
107fn current_op(p: &Parser) -> (u8, Op) {
108 if let Some(t) = p.next3() {
109 match t {
110 (L_ANGLE, L_ANGLE, EQ) =>
111 return (1, Op::Composite(SHLEQ, 3)),
112 (R_ANGLE, R_ANGLE, EQ) =>
113 return (1, Op::Composite(SHREQ, 3)),
114 _ => (),
115 }
116 }
117
118 if let Some(t) = p.next2() {
119 match t {
120 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)),
121 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)),
122 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)),
123 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)),
124 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)),
125 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)),
126 (CARET, EQ) => return (1, Op::Composite(CARETEQ, 2)),
127 (PIPE, PIPE) => return (3, Op::Composite(PIPEPIPE, 2)),
128 (AMP, AMP) => return (4, Op::Composite(AMPAMP, 2)),
129 (L_ANGLE, EQ) => return (5, Op::Composite(LTEQ, 2)),
130 (R_ANGLE, EQ) => return (5, Op::Composite(GTEQ, 2)),
131 (L_ANGLE, L_ANGLE) => return (9, Op::Composite(SHL, 2)),
132 (R_ANGLE, R_ANGLE) => return (9, Op::Composite(SHR, 2)),
133 _ => (),
134 }
135 }
136
137 let bp = match p.current() {
138 EQ => 1,
139 DOTDOT => 2,
140 EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
141 PIPE => 6,
142 CARET => 7,
143 AMP => 8,
144 MINUS | PLUS => 10,
145 STAR | SLASH | PERCENT => 11,
146 _ => 0,
147 };
148 (bp, Op::Simple)
149}
150
151// Parses expression with binding power of at least bp.
152fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
153 let mut lhs = match lhs(p, r) {
154 Some(lhs) => {
155 // test stmt_bin_expr_ambiguity
156 // fn foo() {
157 // let _ = {1} & 2;
158 // {1} &2;
159 // }
160 if r.prefer_stmt && is_block(lhs.kind()) {
161 return BlockLike::Block;
162 }
163 lhs
164 }
165 None => return BlockLike::NotBlock,
166 };
167
168 loop {
169 let is_range = p.current() == DOTDOT;
170 let (op_bp, op) = current_op(p);
171 if op_bp < bp {
172 break;
173 }
174 let m = lhs.precede(p);
175 match op {
176 Op::Simple => p.bump(),
177 Op::Composite(kind, n) => {
178 p.bump_compound(kind, n);
179 }
180 }
181 expr_bp(p, r, op_bp + 1);
182 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
183 }
184 BlockLike::NotBlock
185}
186
187// test no_semi_after_block
188// fn foo() {
189// if true {}
190// loop {}
191// match () {}
192// while true {}
193// for _ in () {}
194// {}
195// {}
196// }
197fn is_block(kind: SyntaxKind) -> bool {
198 match kind {
199 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => true,
200 _ => false,
201 }
202}
203
204const LHS_FIRST: TokenSet =
205 token_set_union![
206 token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
207 atom::ATOM_EXPR_FIRST,
208 ];
209
210fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
211 let m;
212 let kind = match p.current() {
213 // test ref_expr
214 // fn foo() {
215 // let _ = &1;
216 // let _ = &mut &f();
217 // }
218 AMP => {
219 m = p.start();
220 p.bump();
221 p.eat(MUT_KW);
222 REF_EXPR
223 }
224 // test unary_expr
225 // fn foo() {
226 // **&1;
227 // !!true;
228 // --1;
229 // }
230 STAR | EXCL | MINUS => {
231 m = p.start();
232 p.bump();
233 PREFIX_EXPR
234 }
235 // test full_range_expr
236 // fn foo() { xs[..]; }
237 DOTDOT => {
238 m = p.start();
239 p.bump();
240 if p.at_ts(EXPR_FIRST) {
241 expr_bp(p, r, 2);
242 }
243 return Some(m.complete(p, RANGE_EXPR));
244 }
245 _ => {
246 let lhs = atom::atom_expr(p, r)?;
247 return Some(postfix_expr(p, r, lhs));
248 }
249 };
250 expr_bp(p, r, 255);
251 Some(m.complete(p, kind))
252}
253
254fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker {
255 let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind());
256 loop {
257 lhs = match p.current() {
258 // test stmt_postfix_expr_ambiguity
259 // fn foo() {
260 // match () {
261 // _ => {}
262 // () => {}
263 // [] => {}
264 // }
265 // }
266 L_PAREN if allow_calls => call_expr(p, lhs),
267 L_BRACK if allow_calls => index_expr(p, lhs),
268 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
269 method_call_expr(p, lhs)
270 } else {
271 field_expr(p, lhs)
272 },
273 DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
274 // test postfix_range
275 // fn foo() { let x = 1..; }
276 DOTDOT if !EXPR_FIRST.contains(p.nth(1)) => {
277 let m = lhs.precede(p);
278 p.bump();
279 m.complete(p, RANGE_EXPR)
280 }
281 QUESTION => try_expr(p, lhs),
282 AS_KW => cast_expr(p, lhs),
283 _ => break,
284 };
285 allow_calls = true
286 }
287 lhs
288}
289
290// test call_expr
291// fn foo() {
292// let _ = f();
293// let _ = f()(1)(1, 2,);
294// }
295fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
296 assert!(p.at(L_PAREN));
297 let m = lhs.precede(p);
298 arg_list(p);
299 m.complete(p, CALL_EXPR)
300}
301
302// test index_expr
303// fn foo() {
304// x[1][2];
305// }
306fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
307 assert!(p.at(L_BRACK));
308 let m = lhs.precede(p);
309 p.bump();
310 expr(p);
311 p.expect(R_BRACK);
312 m.complete(p, INDEX_EXPR)
313}
314
315// test method_call_expr
316// fn foo() {
317// x.foo();
318// y.bar::<T>(1, 2,);
319// }
320fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
321 assert!(
322 p.at(DOT) && p.nth(1) == IDENT
323 && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)
324 );
325 let m = lhs.precede(p);
326 p.bump();
327 name_ref(p);
328 type_args::opt_type_arg_list(p, true);
329 if p.at(L_PAREN) {
330 arg_list(p);
331 }
332 m.complete(p, METHOD_CALL_EXPR)
333}
334
335// test field_expr
336// fn foo() {
337// x.foo;
338// x.0.bar;
339// }
340fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
341 assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
342 let m = lhs.precede(p);
343 p.bump();
344 if p.at(IDENT) {
345 name_ref(p)
346 } else {
347 p.bump()
348 }
349 m.complete(p, FIELD_EXPR)
350}
351
352// test try_expr
353// fn foo() {
354// x?;
355// }
356fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
357 assert!(p.at(QUESTION));
358 let m = lhs.precede(p);
359 p.bump();
360 m.complete(p, TRY_EXPR)
361}
362
363// test cast_expr
364// fn foo() {
365// 82 as i32;
366// }
367fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
368 assert!(p.at(AS_KW));
369 let m = lhs.precede(p);
370 p.bump();
371 types::type_(p);
372 m.complete(p, CAST_EXPR)
373}
374
375fn arg_list(p: &mut Parser) {
376 assert!(p.at(L_PAREN));
377 let m = p.start();
378 p.bump();
379 while !p.at(R_PAREN) && !p.at(EOF) {
380 if !p.at_ts(EXPR_FIRST) {
381 p.error("expected expression");
382 break;
383 }
384 expr(p);
385 if !p.at(R_PAREN) && !p.expect(COMMA) {
386 break;
387 }
388 }
389 p.eat(R_PAREN);
390 m.complete(p, ARG_LIST);
391}
392
393// test path_expr
394// fn foo() {
395// let _ = a;
396// let _ = a::b;
397// let _ = ::a::<b>;
398// let _ = format!();
399// }
400fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
401 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
402 let m = p.start();
403 paths::expr_path(p);
404 match p.current() {
405 L_CURLY if !r.forbid_structs => {
406 named_field_list(p);
407 m.complete(p, STRUCT_LIT)
408 }
409 EXCL => {
410 items::macro_call_after_excl(p);
411 m.complete(p, MACRO_CALL)
412 }
413 _ => m.complete(p, PATH_EXPR)
414 }
415}
416
417// test struct_lit
418// fn foo() {
419// S {};
420// S { x, y: 32, };
421// S { x, y: 32, ..Default::default() };
422// }
423pub(crate) fn named_field_list(p: &mut Parser) {
424 assert!(p.at(L_CURLY));
425 let m = p.start();
426 p.bump();
427 while !p.at(EOF) && !p.at(R_CURLY) {
428 match p.current() {
429 IDENT => {
430 let m = p.start();
431 name_ref(p);
432 if p.eat(COLON) {
433 expr(p);
434 }
435 m.complete(p, NAMED_FIELD);
436 }
437 DOTDOT => {
438 p.bump();
439 expr(p);
440 }
441 L_CURLY => error_block(p, "expected a field"),
442 _ => p.err_and_bump("expected identifier"),
443 }
444 if !p.at(R_CURLY) {
445 p.expect(COMMA);
446 }
447 }
448 p.expect(R_CURLY);
449 m.complete(p, NAMED_FIELD_LIST);
450}