diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/grammar/expressions.rs | 72 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/expressions/atom.rs | 13 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/patterns.rs | 8 | ||||
-rw-r--r-- | crates/ra_syntax/src/parser_api.rs | 2 |
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. |
159 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | 173 | fn 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 | // } | ||
204 | fn 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 | |||
211 | const LHS_FIRST: TokenSet = token_set_union![ | 208 | const 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 | ||
216 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { | 213 | fn 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 | ||
260 | fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker { | 260 | fn 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 | // } |
409 | fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { | 415 | fn 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 | ||
62 | const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; | 62 | const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; |
63 | 63 | ||
64 | pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { | 64 | pub(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 | } |