aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/grammar/expressions.rs72
-rw-r--r--crates/ra_syntax/src/grammar/expressions/atom.rs13
-rw-r--r--crates/ra_syntax/src/grammar/patterns.rs8
-rw-r--r--crates/ra_syntax/src/parser_api.rs2
4 files changed, 55 insertions, 40 deletions
diff --git a/crates/ra_syntax/src/grammar/expressions.rs b/crates/ra_syntax/src/grammar/expressions.rs
index a9449c7bf..4f8c46ab3 100644
--- a/crates/ra_syntax/src/grammar/expressions.rs
+++ b/crates/ra_syntax/src/grammar/expressions.rs
@@ -64,6 +64,20 @@ pub(crate) fn block(p: &mut Parser) {
64 if p.at(R_CURLY) { 64 if p.at(R_CURLY) {
65 m.abandon(p); 65 m.abandon(p);
66 } else { 66 } else {
67 // test no_semi_after_block
68 // fn foo() {
69 // if true {}
70 // loop {}
71 // match () {}
72 // while true {}
73 // for _ in () {}
74 // {}
75 // {}
76 // macro_rules! test {
77 // () => {}
78 // }
79 // test!{}
80 // }
67 if is_blocklike { 81 if is_blocklike {
68 p.eat(SEMI); 82 p.eat(SEMI);
69 } else { 83 } else {
@@ -143,7 +157,7 @@ fn current_op(p: &Parser) -> (u8, Op) {
143 157
144 let bp = match p.current() { 158 let bp = match p.current() {
145 EQ => 1, 159 EQ => 1,
146 DOTDOT => 2, 160 DOTDOT | DOTDOTEQ => 2,
147 EQEQ | NEQ | L_ANGLE | R_ANGLE => 5, 161 EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
148 PIPE => 6, 162 PIPE => 6,
149 CARET => 7, 163 CARET => 7,
@@ -158,13 +172,13 @@ fn current_op(p: &Parser) -> (u8, Op) {
158// Parses expression with binding power of at least bp. 172// Parses expression with binding power of at least bp.
159fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { 173fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
160 let mut lhs = match lhs(p, r) { 174 let mut lhs = match lhs(p, r) {
161 Some(lhs) => { 175 Some((lhs, blocklike)) => {
162 // test stmt_bin_expr_ambiguity 176 // test stmt_bin_expr_ambiguity
163 // fn foo() { 177 // fn foo() {
164 // let _ = {1} & 2; 178 // let _ = {1} & 2;
165 // {1} &2; 179 // {1} &2;
166 // } 180 // }
167 if r.prefer_stmt && is_block(lhs.kind()) { 181 if r.prefer_stmt && blocklike.is_block() {
168 return BlockLike::Block; 182 return BlockLike::Block;
169 } 183 }
170 lhs 184 lhs
@@ -173,7 +187,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
173 }; 187 };
174 188
175 loop { 189 loop {
176 let is_range = p.current() == DOTDOT; 190 let is_range = p.current() == DOTDOT || p.current() == DOTDOTEQ;
177 let (op_bp, op) = current_op(p); 191 let (op_bp, op) = current_op(p);
178 if op_bp < bp { 192 if op_bp < bp {
179 break; 193 break;
@@ -191,29 +205,12 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
191 BlockLike::NotBlock 205 BlockLike::NotBlock
192} 206}
193 207
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![ 208const LHS_FIRST: TokenSet = token_set_union![
212 token_set![AMP, STAR, EXCL, DOTDOT, MINUS], 209 token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
213 atom::ATOM_EXPR_FIRST, 210 atom::ATOM_EXPR_FIRST,
214]; 211];
215 212
216fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { 213fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
217 let m; 214 let m;
218 let kind = match p.current() { 215 let kind = match p.current() {
219 // test ref_expr 216 // test ref_expr
@@ -246,19 +243,28 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
246 if p.at_ts(EXPR_FIRST) { 243 if p.at_ts(EXPR_FIRST) {
247 expr_bp(p, r, 2); 244 expr_bp(p, r, 2);
248 } 245 }
249 return Some(m.complete(p, RANGE_EXPR)); 246 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
250 } 247 }
251 _ => { 248 _ => {
252 let lhs = atom::atom_expr(p, r)?; 249 let (lhs, blocklike) = atom::atom_expr(p, r)?;
253 return Some(postfix_expr(p, r, lhs)); 250 return Some((
251 postfix_expr(p, lhs, !(r.prefer_stmt && blocklike.is_block())),
252 blocklike,
253 ));
254 } 254 }
255 }; 255 };
256 expr_bp(p, r, 255); 256 expr_bp(p, r, 255);
257 Some(m.complete(p, kind)) 257 Some((m.complete(p, kind), BlockLike::NotBlock))
258} 258}
259 259
260fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker { 260fn postfix_expr(
261 let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind()); 261 p: &mut Parser,
262 mut lhs: CompletedMarker,
263 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
264 // E.g. `while true {break}();` is parsed as
265 // `while true {break}; ();`
266 mut allow_calls: bool,
267) -> CompletedMarker {
262 loop { 268 loop {
263 lhs = match p.current() { 269 lhs = match p.current() {
264 // test stmt_postfix_expr_ambiguity 270 // test stmt_postfix_expr_ambiguity
@@ -406,20 +412,20 @@ fn arg_list(p: &mut Parser) {
406// let _ = ::a::<b>; 412// let _ = ::a::<b>;
407// let _ = format!(); 413// let _ = format!();
408// } 414// }
409fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { 415fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
410 assert!(paths::is_path_start(p) || p.at(L_ANGLE)); 416 assert!(paths::is_path_start(p) || p.at(L_ANGLE));
411 let m = p.start(); 417 let m = p.start();
412 paths::expr_path(p); 418 paths::expr_path(p);
413 match p.current() { 419 match p.current() {
414 L_CURLY if !r.forbid_structs => { 420 L_CURLY if !r.forbid_structs => {
415 named_field_list(p); 421 named_field_list(p);
416 m.complete(p, STRUCT_LIT) 422 (m.complete(p, STRUCT_LIT), BlockLike::Block)
417 } 423 }
418 EXCL => { 424 EXCL => {
419 items::macro_call_after_excl(p); 425 let block_like = items::macro_call_after_excl(p);
420 m.complete(p, MACRO_CALL) 426 return (m.complete(p, MACRO_CALL), block_like);
421 } 427 }
422 _ => m.complete(p, PATH_EXPR), 428 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
423 } 429 }
424} 430}
425 431
diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs
index 04087fd60..cd7d62aff 100644
--- a/crates/ra_syntax/src/grammar/expressions/atom.rs
+++ b/crates/ra_syntax/src/grammar/expressions/atom.rs
@@ -61,9 +61,9 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = token_set_union![
61 61
62const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; 62const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
63 63
64pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { 64pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
65 if let Some(m) = literal(p) { 65 if let Some(m) = literal(p) {
66 return Some(m); 66 return Some((m, BlockLike::NotBlock));
67 } 67 }
68 if paths::is_path_start(p) || p.at(L_ANGLE) { 68 if paths::is_path_start(p) || p.at(L_ANGLE) {
69 return Some(path_expr(p, r)); 69 return Some(path_expr(p, r));
@@ -114,7 +114,11 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark
114 return None; 114 return None;
115 } 115 }
116 }; 116 };
117 Some(done) 117 let blocklike = match done.kind() {
118 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
119 _ => BlockLike::NotBlock,
120 };
121 Some((done, blocklike))
118} 122}
119 123
120// test tuple_expr 124// test tuple_expr
@@ -349,6 +353,7 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
349// fn foo() { 353// fn foo() {
350// match () { 354// match () {
351// _ => (), 355// _ => (),
356// _ if Test>{field: 0} => (),
352// X | Y if Z => (), 357// X | Y if Z => (),
353// | X | Y if Z => (), 358// | X | Y if Z => (),
354// | X => (), 359// | X => (),
@@ -362,7 +367,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
362 patterns::pattern(p); 367 patterns::pattern(p);
363 } 368 }
364 if p.eat(IF_KW) { 369 if p.eat(IF_KW) {
365 expr_no_struct(p); 370 expr(p);
366 } 371 }
367 p.expect(FAT_ARROW); 372 p.expect(FAT_ARROW);
368 let ret = expr_stmt(p); 373 let ret = expr_stmt(p);
diff --git a/crates/ra_syntax/src/grammar/patterns.rs b/crates/ra_syntax/src/grammar/patterns.rs
index 10fa0e0be..64cdf0b1b 100644
--- a/crates/ra_syntax/src/grammar/patterns.rs
+++ b/crates/ra_syntax/src/grammar/patterns.rs
@@ -14,9 +14,13 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
14 if let Some(lhs) = atom_pat(p, recovery_set) { 14 if let Some(lhs) = atom_pat(p, recovery_set) {
15 // test range_pat 15 // test range_pat
16 // fn main() { 16 // fn main() {
17 // match 92 { 0 ... 100 => () } 17 // match 92 {
18 // 0 ... 100 => (),
19 // 101 ..= 200 => (),
20 // 200 .. 301=> (),
21 // }
18 // } 22 // }
19 if p.at(DOTDOTDOT) { 23 if p.at(DOTDOTDOT) || p.at(DOTDOTEQ) || p.at(DOTDOT) {
20 let m = lhs.precede(p); 24 let m = lhs.precede(p);
21 p.bump(); 25 p.bump();
22 atom_pat(p, recovery_set); 26 atom_pat(p, recovery_set);
diff --git a/crates/ra_syntax/src/parser_api.rs b/crates/ra_syntax/src/parser_api.rs
index c37c30e34..02421def1 100644
--- a/crates/ra_syntax/src/parser_api.rs
+++ b/crates/ra_syntax/src/parser_api.rs
@@ -36,7 +36,7 @@ impl<'t> Parser<'t> {
36 self.current() == kind 36 self.current() == kind
37 } 37 }
38 38
39 /// Checks if the current token is `kind`. 39 /// Checks if the current token is in `kinds`.
40 pub(crate) fn at_ts(&self, kinds: TokenSet) -> bool { 40 pub(crate) fn at_ts(&self, kinds: TokenSet) -> bool {
41 kinds.contains(self.current()) 41 kinds.contains(self.current())
42 } 42 }