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