diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/grammar/expressions.rs | 77 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/expressions/atom.rs | 20 |
2 files changed, 43 insertions, 54 deletions
diff --git a/crates/ra_syntax/src/grammar/expressions.rs b/crates/ra_syntax/src/grammar/expressions.rs index 9d75bfb90..5f5a3077d 100644 --- a/crates/ra_syntax/src/grammar/expressions.rs +++ b/crates/ra_syntax/src/grammar/expressions.rs | |||
@@ -64,6 +64,16 @@ 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 | // } | ||
67 | if is_blocklike { | 77 | if is_blocklike { |
68 | p.eat(SEMI); | 78 | p.eat(SEMI); |
69 | } else { | 79 | } else { |
@@ -158,19 +168,18 @@ fn current_op(p: &Parser) -> (u8, Op) { | |||
158 | // Parses expression with binding power of at least bp. | 168 | // Parses expression with binding power of at least bp. |
159 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | 169 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { |
160 | let mut lhs = match lhs(p, r) { | 170 | let mut lhs = match lhs(p, r) { |
161 | (Some(lhs), macro_blocklike) => { | 171 | Some((lhs, macro_blocklike)) => { |
162 | // test stmt_bin_expr_ambiguity | 172 | // test stmt_bin_expr_ambiguity |
163 | // fn foo() { | 173 | // fn foo() { |
164 | // let _ = {1} & 2; | 174 | // let _ = {1} & 2; |
165 | // {1} &2; | 175 | // {1} &2; |
166 | // } | 176 | // } |
167 | if r.prefer_stmt && (is_block(lhs.kind()) || macro_blocklike == Some(BlockLike::Block)) | 177 | if r.prefer_stmt && macro_blocklike.is_block() { |
168 | { | ||
169 | return BlockLike::Block; | 178 | return BlockLike::Block; |
170 | } | 179 | } |
171 | lhs | 180 | lhs |
172 | } | 181 | } |
173 | (None, _) => return BlockLike::NotBlock, | 182 | None => return BlockLike::NotBlock, |
174 | }; | 183 | }; |
175 | 184 | ||
176 | loop { | 185 | loop { |
@@ -192,29 +201,12 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | |||
192 | BlockLike::NotBlock | 201 | BlockLike::NotBlock |
193 | } | 202 | } |
194 | 203 | ||
195 | // test no_semi_after_block | ||
196 | // fn foo() { | ||
197 | // if true {} | ||
198 | // loop {} | ||
199 | // match () {} | ||
200 | // while true {} | ||
201 | // for _ in () {} | ||
202 | // {} | ||
203 | // {} | ||
204 | // } | ||
205 | fn is_block(kind: SyntaxKind) -> bool { | ||
206 | match kind { | ||
207 | IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => true, | ||
208 | _ => false, | ||
209 | } | ||
210 | } | ||
211 | |||
212 | const LHS_FIRST: TokenSet = token_set_union![ | 204 | const LHS_FIRST: TokenSet = token_set_union![ |
213 | token_set![AMP, STAR, EXCL, DOTDOT, MINUS], | 205 | token_set![AMP, STAR, EXCL, DOTDOT, MINUS], |
214 | atom::ATOM_EXPR_FIRST, | 206 | atom::ATOM_EXPR_FIRST, |
215 | ]; | 207 | ]; |
216 | 208 | ||
217 | fn lhs(p: &mut Parser, r: Restrictions) -> (Option<CompletedMarker>, Option<BlockLike>) { | 209 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { |
218 | let m; | 210 | let m; |
219 | let kind = match p.current() { | 211 | let kind = match p.current() { |
220 | // test ref_expr | 212 | // test ref_expr |
@@ -247,30 +239,28 @@ fn lhs(p: &mut Parser, r: Restrictions) -> (Option<CompletedMarker>, Option<Bloc | |||
247 | if p.at_ts(EXPR_FIRST) { | 239 | if p.at_ts(EXPR_FIRST) { |
248 | expr_bp(p, r, 2); | 240 | expr_bp(p, r, 2); |
249 | } | 241 | } |
250 | return (Some(m.complete(p, RANGE_EXPR)), None); | 242 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); |
251 | } | 243 | } |
252 | _ => { | 244 | _ => { |
253 | let (lhs_marker, macro_block_like) = atom::atom_expr(p, r); | 245 | let (lhs, blocklike) = atom::atom_expr(p, r)?; |
254 | 246 | return Some(( | |
255 | if macro_block_like == Some(BlockLike::Block) { | 247 | postfix_expr(p, lhs, !(r.prefer_stmt && blocklike.is_block())), |
256 | return (lhs_marker, macro_block_like); | 248 | blocklike, |
257 | } | 249 | )); |
258 | if let Some(lhs_marker) = lhs_marker { | ||
259 | return (Some(postfix_expr(p, r, lhs_marker)), macro_block_like); | ||
260 | } else { | ||
261 | return (None, None); | ||
262 | } | ||
263 | } | 250 | } |
264 | }; | 251 | }; |
265 | expr_bp(p, r, 255); | 252 | expr_bp(p, r, 255); |
266 | (Some(m.complete(p, kind)), None) | 253 | Some((m.complete(p, kind), BlockLike::NotBlock)) |
267 | } | 254 | } |
268 | 255 | ||
269 | fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker { | 256 | fn postfix_expr( |
257 | p: &mut Parser, | ||
258 | mut lhs: CompletedMarker, | ||
270 | // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple | 259 | // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple |
271 | // E.g. `while true {break}();` is parsed as | 260 | // E.g. `while true {break}();` is parsed as |
272 | // `while true {break}; ();` | 261 | // `while true {break}; ();` |
273 | let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind()); | 262 | mut allow_calls: bool, |
263 | ) -> CompletedMarker { | ||
274 | loop { | 264 | loop { |
275 | lhs = match p.current() { | 265 | lhs = match p.current() { |
276 | // test stmt_postfix_expr_ambiguity | 266 | // test stmt_postfix_expr_ambiguity |
@@ -418,22 +408,21 @@ fn arg_list(p: &mut Parser) { | |||
418 | // let _ = ::a::<b>; | 408 | // let _ = ::a::<b>; |
419 | // let _ = format!(); | 409 | // let _ = format!(); |
420 | // } | 410 | // } |
421 | fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, Option<BlockLike>) { | 411 | fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { |
422 | assert!(paths::is_path_start(p) || p.at(L_ANGLE)); | 412 | assert!(paths::is_path_start(p) || p.at(L_ANGLE)); |
423 | let m = p.start(); | 413 | let m = p.start(); |
424 | paths::expr_path(p); | 414 | paths::expr_path(p); |
425 | let res = match p.current() { | 415 | match p.current() { |
426 | L_CURLY if !r.forbid_structs => { | 416 | L_CURLY if !r.forbid_structs => { |
427 | named_field_list(p); | 417 | named_field_list(p); |
428 | m.complete(p, STRUCT_LIT) | 418 | (m.complete(p, STRUCT_LIT), BlockLike::Block) |
429 | } | 419 | } |
430 | EXCL => { | 420 | EXCL => { |
431 | let block_like = items::macro_call_after_excl(p); // TODO: Use return type (BlockLike) | 421 | let block_like = items::macro_call_after_excl(p); |
432 | return (m.complete(p, MACRO_CALL), Some(block_like)); | 422 | return (m.complete(p, MACRO_CALL), block_like); |
433 | } | 423 | } |
434 | _ => m.complete(p, PATH_EXPR), | 424 | _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock), |
435 | }; | 425 | } |
436 | (res, None) | ||
437 | } | 426 | } |
438 | 427 | ||
439 | // test struct_lit | 428 | // test struct_lit |
diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs index 471f398f5..a976799e7 100644 --- a/crates/ra_syntax/src/grammar/expressions/atom.rs +++ b/crates/ra_syntax/src/grammar/expressions/atom.rs | |||
@@ -61,16 +61,12 @@ 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( | 64 | pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { |
65 | p: &mut Parser, | ||
66 | r: Restrictions, | ||
67 | ) -> (Option<CompletedMarker>, Option<BlockLike>) { | ||
68 | if let Some(m) = literal(p) { | 65 | if let Some(m) = literal(p) { |
69 | return (Some(m), None); | 66 | return Some((m, BlockLike::NotBlock)); |
70 | } | 67 | } |
71 | if paths::is_path_start(p) || p.at(L_ANGLE) { | 68 | if paths::is_path_start(p) || p.at(L_ANGLE) { |
72 | let path_expr = path_expr(p, r); | 69 | return Some(path_expr(p, r)); |
73 | return (Some(path_expr.0), path_expr.1); | ||
74 | } | 70 | } |
75 | let la = p.nth(1); | 71 | let la = p.nth(1); |
76 | let done = match p.current() { | 72 | let done = match p.current() { |
@@ -98,7 +94,7 @@ pub(super) fn atom_expr( | |||
98 | // } | 94 | // } |
99 | p.error("expected a loop"); | 95 | p.error("expected a loop"); |
100 | m.complete(p, ERROR); | 96 | m.complete(p, ERROR); |
101 | return (None, None); | 97 | return None; |
102 | } | 98 | } |
103 | } | 99 | } |
104 | } | 100 | } |
@@ -115,10 +111,14 @@ pub(super) fn atom_expr( | |||
115 | BREAK_KW => break_expr(p), | 111 | BREAK_KW => break_expr(p), |
116 | _ => { | 112 | _ => { |
117 | p.err_recover("expected expression", EXPR_RECOVERY_SET); | 113 | p.err_recover("expected expression", EXPR_RECOVERY_SET); |
118 | return (None, None); | 114 | return None; |
119 | } | 115 | } |
120 | }; | 116 | }; |
121 | (Some(done), None) | 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)) | ||
122 | } | 122 | } |
123 | 123 | ||
124 | // test tuple_expr | 124 | // test tuple_expr |