diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/grammar/expressions.rs | 39 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar/expressions/atom.rs | 16 |
2 files changed, 36 insertions, 19 deletions
diff --git a/crates/ra_syntax/src/grammar/expressions.rs b/crates/ra_syntax/src/grammar/expressions.rs index 512823ddf..9d75bfb90 100644 --- a/crates/ra_syntax/src/grammar/expressions.rs +++ b/crates/ra_syntax/src/grammar/expressions.rs | |||
@@ -158,18 +158,19 @@ fn current_op(p: &Parser) -> (u8, Op) { | |||
158 | // Parses expression with binding power of at least bp. | 158 | // Parses expression with binding power of at least bp. |
159 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | 159 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { |
160 | let mut lhs = match lhs(p, r) { | 160 | let mut lhs = match lhs(p, r) { |
161 | Some(lhs) => { | 161 | (Some(lhs), macro_blocklike) => { |
162 | // test stmt_bin_expr_ambiguity | 162 | // test stmt_bin_expr_ambiguity |
163 | // fn foo() { | 163 | // fn foo() { |
164 | // let _ = {1} & 2; | 164 | // let _ = {1} & 2; |
165 | // {1} &2; | 165 | // {1} &2; |
166 | // } | 166 | // } |
167 | if r.prefer_stmt && is_block(lhs.kind()) { | 167 | if r.prefer_stmt && (is_block(lhs.kind()) || macro_blocklike == Some(BlockLike::Block)) |
168 | { | ||
168 | return BlockLike::Block; | 169 | return BlockLike::Block; |
169 | } | 170 | } |
170 | lhs | 171 | lhs |
171 | } | 172 | } |
172 | None => return BlockLike::NotBlock, | 173 | (None, _) => return BlockLike::NotBlock, |
173 | }; | 174 | }; |
174 | 175 | ||
175 | loop { | 176 | loop { |
@@ -213,7 +214,7 @@ const LHS_FIRST: TokenSet = token_set_union![ | |||
213 | atom::ATOM_EXPR_FIRST, | 214 | atom::ATOM_EXPR_FIRST, |
214 | ]; | 215 | ]; |
215 | 216 | ||
216 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { | 217 | fn lhs(p: &mut Parser, r: Restrictions) -> (Option<CompletedMarker>, Option<BlockLike>) { |
217 | let m; | 218 | let m; |
218 | let kind = match p.current() { | 219 | let kind = match p.current() { |
219 | // test ref_expr | 220 | // test ref_expr |
@@ -246,18 +247,29 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> { | |||
246 | if p.at_ts(EXPR_FIRST) { | 247 | if p.at_ts(EXPR_FIRST) { |
247 | expr_bp(p, r, 2); | 248 | expr_bp(p, r, 2); |
248 | } | 249 | } |
249 | return Some(m.complete(p, RANGE_EXPR)); | 250 | return (Some(m.complete(p, RANGE_EXPR)), None); |
250 | } | 251 | } |
251 | _ => { | 252 | _ => { |
252 | let lhs = atom::atom_expr(p, r)?; | 253 | let (lhs_marker, macro_block_like) = atom::atom_expr(p, r); |
253 | return Some(postfix_expr(p, r, lhs)); | 254 | |
255 | if macro_block_like == Some(BlockLike::Block) { | ||
256 | return (lhs_marker, macro_block_like); | ||
257 | } | ||
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 | } | ||
254 | } | 263 | } |
255 | }; | 264 | }; |
256 | expr_bp(p, r, 255); | 265 | expr_bp(p, r, 255); |
257 | Some(m.complete(p, kind)) | 266 | (Some(m.complete(p, kind)), None) |
258 | } | 267 | } |
259 | 268 | ||
260 | fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker { | 269 | fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker { |
270 | // 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 | ||
272 | // `while true {break}; ();` | ||
261 | let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind()); | 273 | let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind()); |
262 | loop { | 274 | loop { |
263 | lhs = match p.current() { | 275 | lhs = match p.current() { |
@@ -406,21 +418,22 @@ fn arg_list(p: &mut Parser) { | |||
406 | // let _ = ::a::<b>; | 418 | // let _ = ::a::<b>; |
407 | // let _ = format!(); | 419 | // let _ = format!(); |
408 | // } | 420 | // } |
409 | fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { | 421 | fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, Option<BlockLike>) { |
410 | assert!(paths::is_path_start(p) || p.at(L_ANGLE)); | 422 | assert!(paths::is_path_start(p) || p.at(L_ANGLE)); |
411 | let m = p.start(); | 423 | let m = p.start(); |
412 | paths::expr_path(p); | 424 | paths::expr_path(p); |
413 | match p.current() { | 425 | let res = match p.current() { |
414 | L_CURLY if !r.forbid_structs => { | 426 | L_CURLY if !r.forbid_structs => { |
415 | named_field_list(p); | 427 | named_field_list(p); |
416 | m.complete(p, STRUCT_LIT) | 428 | m.complete(p, STRUCT_LIT) |
417 | } | 429 | } |
418 | EXCL => { | 430 | EXCL => { |
419 | items::macro_call_after_excl(p); // TODO: Use return type (BlockLike) | 431 | let block_like = items::macro_call_after_excl(p); // TODO: Use return type (BlockLike) |
420 | m.complete(p, MACRO_CALL) | 432 | return (m.complete(p, MACRO_CALL), Some(block_like)); |
421 | } | 433 | } |
422 | _ => m.complete(p, PATH_EXPR), | 434 | _ => m.complete(p, PATH_EXPR), |
423 | } | 435 | }; |
436 | (res, None) | ||
424 | } | 437 | } |
425 | 438 | ||
426 | // test struct_lit | 439 | // test struct_lit |
diff --git a/crates/ra_syntax/src/grammar/expressions/atom.rs b/crates/ra_syntax/src/grammar/expressions/atom.rs index 452e91485..471f398f5 100644 --- a/crates/ra_syntax/src/grammar/expressions/atom.rs +++ b/crates/ra_syntax/src/grammar/expressions/atom.rs | |||
@@ -61,12 +61,16 @@ 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( |
65 | p: &mut Parser, | ||
66 | r: Restrictions, | ||
67 | ) -> (Option<CompletedMarker>, Option<BlockLike>) { | ||
65 | if let Some(m) = literal(p) { | 68 | if let Some(m) = literal(p) { |
66 | return Some(m); | 69 | return (Some(m), None); |
67 | } | 70 | } |
68 | if paths::is_path_start(p) || p.at(L_ANGLE) { | 71 | if paths::is_path_start(p) || p.at(L_ANGLE) { |
69 | return Some(path_expr(p, r)); | 72 | let path_expr = path_expr(p, r); |
73 | return (Some(path_expr.0), path_expr.1); | ||
70 | } | 74 | } |
71 | let la = p.nth(1); | 75 | let la = p.nth(1); |
72 | let done = match p.current() { | 76 | let done = match p.current() { |
@@ -94,7 +98,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark | |||
94 | // } | 98 | // } |
95 | p.error("expected a loop"); | 99 | p.error("expected a loop"); |
96 | m.complete(p, ERROR); | 100 | m.complete(p, ERROR); |
97 | return None; | 101 | return (None, None); |
98 | } | 102 | } |
99 | } | 103 | } |
100 | } | 104 | } |
@@ -111,10 +115,10 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark | |||
111 | BREAK_KW => break_expr(p), | 115 | BREAK_KW => break_expr(p), |
112 | _ => { | 116 | _ => { |
113 | p.err_recover("expected expression", EXPR_RECOVERY_SET); | 117 | p.err_recover("expected expression", EXPR_RECOVERY_SET); |
114 | return None; | 118 | return (None, None); |
115 | } | 119 | } |
116 | }; | 120 | }; |
117 | Some(done) | 121 | (Some(done), None) |
118 | } | 122 | } |
119 | 123 | ||
120 | // test tuple_expr | 124 | // test tuple_expr |