aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/expressions.rs
diff options
context:
space:
mode:
authorDmitry <[email protected]>2020-08-14 19:32:05 +0100
committerDmitry <[email protected]>2020-08-14 19:32:05 +0100
commit178c3e135a2a249692f7784712492e7884ae0c00 (patch)
treeac6b769dbf7162150caa0c1624786a4dd79ff3be /crates/parser/src/grammar/expressions.rs
parent06ff8e6c760ff05f10e868b5d1f9d79e42fbb49c (diff)
parentc2594daf2974dbd4ce3d9b7ec72481764abaceb5 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'crates/parser/src/grammar/expressions.rs')
-rw-r--r--crates/parser/src/grammar/expressions.rs651
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
3mod atom;
4
5pub(crate) use self::atom::{block_expr, match_arm_list};
6pub(super) use self::atom::{literal, LITERAL_FIRST};
7use super::*;
8
9pub(super) enum StmtWithSemi {
10 Yes,
11 No,
12 Optional,
13}
14
15const EXPR_FIRST: TokenSet = LHS_FIRST;
16
17pub(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
22pub(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
42pub(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
47fn expr_no_struct(p: &mut Parser) {
48 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
49 expr_bp(p, r, 1);
50}
51
52fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
53 let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR);
54 !forbid
55}
56
57pub(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
176pub(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)]
206struct 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]
215fn 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.
257fn 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
318const LHS_FIRST: TokenSet =
319 atom::ATOM_EXPR_FIRST.union(token_set![T![&], T![*], T![!], T![.], T![-]]);
320
321fn 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
389fn 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// }
462fn 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// }
473fn 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// }
487fn 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// }
512fn 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// }
531fn 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// }
545fn 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
555fn 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// }
582fn 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// }
606pub(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}