aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src/grammar/expressions/atom.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src/grammar/expressions/atom.rs')
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs475
1 files changed, 475 insertions, 0 deletions
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..e74305b6a
--- /dev/null
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -0,0 +1,475 @@
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 = token_set![
17 TRUE_KW,
18 FALSE_KW,
19 INT_NUMBER,
20 FLOAT_NUMBER,
21 BYTE,
22 CHAR,
23 STRING,
24 RAW_STRING,
25 BYTE_STRING,
26 RAW_BYTE_STRING
27];
28
29pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
30 if !p.at_ts(LITERAL_FIRST) {
31 return None;
32 }
33 let m = p.start();
34 p.bump();
35 Some(m.complete(p, LITERAL))
36}
37
38// E.g. for after the break in `if break {}`, this should not match
39pub(super) const ATOM_EXPR_FIRST: TokenSet =
40 LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![
41 L_PAREN,
42 L_CURLY,
43 L_BRACK,
44 PIPE,
45 MOVE_KW,
46 IF_KW,
47 WHILE_KW,
48 MATCH_KW,
49 UNSAFE_KW,
50 RETURN_KW,
51 BREAK_KW,
52 CONTINUE_KW,
53 LIFETIME,
54 ]);
55
56const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
57
58pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
59 if let Some(m) = literal(p) {
60 return Some((m, BlockLike::NotBlock));
61 }
62 if paths::is_path_start(p) || p.at(L_ANGLE) {
63 return Some(path_expr(p, r));
64 }
65 let la = p.nth(1);
66 let done = match p.current() {
67 L_PAREN => tuple_expr(p),
68 L_BRACK => array_expr(p),
69 PIPE => lambda_expr(p),
70 MOVE_KW if la == PIPE => lambda_expr(p),
71 IF_KW => if_expr(p),
72
73 LOOP_KW => loop_expr(p, None),
74 FOR_KW => for_expr(p, None),
75 WHILE_KW => while_expr(p, None),
76 LIFETIME if la == COLON => {
77 let m = p.start();
78 label(p);
79 match p.current() {
80 LOOP_KW => loop_expr(p, Some(m)),
81 FOR_KW => for_expr(p, Some(m)),
82 WHILE_KW => while_expr(p, Some(m)),
83 L_CURLY => block_expr(p, Some(m)),
84 _ => {
85 // test_err misplaced_label_err
86 // fn main() {
87 // 'loop: impl
88 // }
89 p.error("expected a loop");
90 m.complete(p, ERROR);
91 return None;
92 }
93 }
94 }
95
96 MATCH_KW => match_expr(p),
97 UNSAFE_KW if la == L_CURLY => {
98 let m = p.start();
99 p.bump();
100 block_expr(p, Some(m))
101 }
102 L_CURLY => block_expr(p, None),
103 RETURN_KW => return_expr(p),
104 CONTINUE_KW => continue_expr(p),
105 BREAK_KW => break_expr(p, r),
106 _ => {
107 p.err_recover("expected expression", EXPR_RECOVERY_SET);
108 return None;
109 }
110 };
111 let blocklike = match done.kind() {
112 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
113 _ => BlockLike::NotBlock,
114 };
115 Some((done, blocklike))
116}
117
118// test tuple_expr
119// fn foo() {
120// ();
121// (1);
122// (1,);
123// }
124fn tuple_expr(p: &mut Parser) -> CompletedMarker {
125 assert!(p.at(L_PAREN));
126 let m = p.start();
127 p.expect(L_PAREN);
128
129 let mut saw_comma = false;
130 let mut saw_expr = false;
131 while !p.at(EOF) && !p.at(R_PAREN) {
132 saw_expr = true;
133 if !p.at_ts(EXPR_FIRST) {
134 p.error("expected expression");
135 break;
136 }
137 expr(p);
138 if !p.at(R_PAREN) {
139 saw_comma = true;
140 p.expect(COMMA);
141 }
142 }
143 p.expect(R_PAREN);
144 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
145}
146
147// test array_expr
148// fn foo() {
149// [];
150// [1];
151// [1, 2,];
152// [1; 2];
153// }
154fn array_expr(p: &mut Parser) -> CompletedMarker {
155 assert!(p.at(L_BRACK));
156 let m = p.start();
157 p.bump();
158 if p.eat(R_BRACK) {
159 return m.complete(p, ARRAY_EXPR);
160 }
161 expr(p);
162 if p.eat(SEMI) {
163 expr(p);
164 p.expect(R_BRACK);
165 return m.complete(p, ARRAY_EXPR);
166 }
167 while !p.at(EOF) && !p.at(R_BRACK) {
168 p.expect(COMMA);
169 if p.at(R_BRACK) {
170 break;
171 }
172 if !p.at_ts(EXPR_FIRST) {
173 p.error("expected expression");
174 break;
175 }
176 expr(p);
177 }
178 p.expect(R_BRACK);
179 m.complete(p, ARRAY_EXPR)
180}
181
182// test lambda_expr
183// fn foo() {
184// || ();
185// || -> i32 { 92 };
186// |x| x;
187// move |x: i32,| x;
188// }
189fn lambda_expr(p: &mut Parser) -> CompletedMarker {
190 assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
191 let m = p.start();
192 p.eat(MOVE_KW);
193 params::param_list_opt_types(p);
194 if opt_fn_ret_type(p) {
195 if !p.at(L_CURLY) {
196 p.error("expected `{`");
197 }
198 }
199 expr(p);
200 m.complete(p, LAMBDA_EXPR)
201}
202
203// test if_expr
204// fn foo() {
205// if true {};
206// if true {} else {};
207// if true {} else if false {} else {};
208// if S {};
209// }
210fn if_expr(p: &mut Parser) -> CompletedMarker {
211 assert!(p.at(IF_KW));
212 let m = p.start();
213 p.bump();
214 cond(p);
215 block(p);
216 if p.at(ELSE_KW) {
217 p.bump();
218 if p.at(IF_KW) {
219 if_expr(p);
220 } else {
221 block(p);
222 }
223 }
224 m.complete(p, IF_EXPR)
225}
226
227// test label
228// fn foo() {
229// 'a: loop {}
230// 'b: while true {}
231// 'c: for x in () {}
232// }
233fn label(p: &mut Parser) {
234 assert!(p.at(LIFETIME) && p.nth(1) == COLON);
235 let m = p.start();
236 p.bump();
237 p.bump();
238 m.complete(p, LABEL);
239}
240
241// test loop_expr
242// fn foo() {
243// loop {};
244// }
245fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
246 assert!(p.at(LOOP_KW));
247 let m = m.unwrap_or_else(|| p.start());
248 p.bump();
249 block(p);
250 m.complete(p, LOOP_EXPR)
251}
252
253// test while_expr
254// fn foo() {
255// while true {};
256// while let Some(x) = it.next() {};
257// }
258fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
259 assert!(p.at(WHILE_KW));
260 let m = m.unwrap_or_else(|| p.start());
261 p.bump();
262 cond(p);
263 block(p);
264 m.complete(p, WHILE_EXPR)
265}
266
267// test for_expr
268// fn foo() {
269// for x in [] {};
270// }
271fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
272 assert!(p.at(FOR_KW));
273 let m = m.unwrap_or_else(|| p.start());
274 p.bump();
275 patterns::pattern(p);
276 p.expect(IN_KW);
277 expr_no_struct(p);
278 block(p);
279 m.complete(p, FOR_EXPR)
280}
281
282// test cond
283// fn foo() { if let Some(_) = None {} }
284fn cond(p: &mut Parser) {
285 let m = p.start();
286 if p.eat(LET_KW) {
287 patterns::pattern(p);
288 p.expect(EQ);
289 }
290 expr_no_struct(p);
291 m.complete(p, CONDITION);
292}
293
294// test match_expr
295// fn foo() {
296// match () { };
297// match S {};
298// }
299fn match_expr(p: &mut Parser) -> CompletedMarker {
300 assert!(p.at(MATCH_KW));
301 let m = p.start();
302 p.bump();
303 expr_no_struct(p);
304 if p.at(L_CURLY) {
305 match_arm_list(p);
306 } else {
307 p.error("expected `{`")
308 }
309 m.complete(p, MATCH_EXPR)
310}
311
312pub(crate) fn match_arm_list(p: &mut Parser) {
313 assert!(p.at(L_CURLY));
314 let m = p.start();
315 p.eat(L_CURLY);
316
317 // test match_arms_inner_attribute
318 // fn foo() {
319 // match () {
320 // #![doc("Inner attribute")]
321 // #![doc("Can be")]
322 // #![doc("Stacked")]
323 // _ => (),
324 // }
325 // }
326 attributes::inner_attributes(p);
327
328 while !p.at(EOF) && !p.at(R_CURLY) {
329 if p.at(L_CURLY) {
330 error_block(p, "expected match arm");
331 continue;
332 }
333
334 // test match_arms_outer_attributes
335 // fn foo() {
336 // match () {
337 // #[cfg(feature = "some")]
338 // _ => (),
339 // #[cfg(feature = "other")]
340 // _ => (),
341 // #[cfg(feature = "many")]
342 // #[cfg(feature = "attributes")]
343 // #[cfg(feature = "before")]
344 // _ => (),
345 // }
346 // }
347 attributes::outer_attributes(p);
348
349 // test match_arms_commas
350 // fn foo() {
351 // match () {
352 // _ => (),
353 // _ => {}
354 // _ => ()
355 // }
356 // }
357 if match_arm(p).is_block() {
358 p.eat(COMMA);
359 } else if !p.at(R_CURLY) {
360 p.expect(COMMA);
361 }
362 }
363 p.expect(R_CURLY);
364 m.complete(p, MATCH_ARM_LIST);
365}
366
367// test match_arm
368// fn foo() {
369// match () {
370// _ => (),
371// _ if Test > Test{field: 0} => (),
372// X | Y if Z => (),
373// | X | Y if Z => (),
374// | X => (),
375// };
376// }
377fn match_arm(p: &mut Parser) -> BlockLike {
378 let m = p.start();
379 p.eat(PIPE);
380 patterns::pattern_r(p, TokenSet::empty());
381 while p.eat(PIPE) {
382 patterns::pattern(p);
383 }
384 if p.at(IF_KW) {
385 match_guard(p);
386 }
387 p.expect(FAT_ARROW);
388 let ret = expr_stmt(p);
389 m.complete(p, MATCH_ARM);
390 ret
391}
392
393// test match_guard
394// fn foo() {
395// match () {
396// _ if foo => (),
397// }
398// }
399fn match_guard(p: &mut Parser) -> CompletedMarker {
400 assert!(p.at(IF_KW));
401 let m = p.start();
402 p.bump();
403 expr(p);
404 m.complete(p, MATCH_GUARD)
405}
406
407// test block_expr
408// fn foo() {
409// {};
410// unsafe {};
411// 'label: {};
412// }
413fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
414 assert!(p.at(L_CURLY));
415 let m = m.unwrap_or_else(|| p.start());
416 block(p);
417 m.complete(p, BLOCK_EXPR)
418}
419
420// test return_expr
421// fn foo() {
422// return;
423// return 92;
424// }
425fn return_expr(p: &mut Parser) -> CompletedMarker {
426 assert!(p.at(RETURN_KW));
427 let m = p.start();
428 p.bump();
429 if p.at_ts(EXPR_FIRST) {
430 expr(p);
431 }
432 m.complete(p, RETURN_EXPR)
433}
434
435// test continue_expr
436// fn foo() {
437// loop {
438// continue;
439// continue 'l;
440// }
441// }
442fn continue_expr(p: &mut Parser) -> CompletedMarker {
443 assert!(p.at(CONTINUE_KW));
444 let m = p.start();
445 p.bump();
446 p.eat(LIFETIME);
447 m.complete(p, CONTINUE_EXPR)
448}
449
450// test break_expr
451// fn foo() {
452// loop {
453// break;
454// break 'l;
455// break 92;
456// break 'l 92;
457// }
458// }
459fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
460 assert!(p.at(BREAK_KW));
461 let m = p.start();
462 p.bump();
463 p.eat(LIFETIME);
464 // test break_ambiguity
465 // fn foo(){
466 // if break {}
467 // while break {}
468 // for i in break {}
469 // match break {}
470 // }
471 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(L_CURLY)) {
472 expr(p);
473 }
474 m.complete(p, BREAK_EXPR)
475}