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