aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/grammar/expressions.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-12-19 21:22:00 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-12-19 21:22:00 +0000
commitef1e107df147a82b74089ab9797ce35effe24e5e (patch)
treee54a25733ffc2c3b19385b299779d763615cb81e /crates/ra_syntax/src/grammar/expressions.rs
parent0e1c01cdb8e6b346edd5d68d9cc72cbce1ce9793 (diff)
parenta3b842fb8b7b5503b1c4fc49355edd4f2fe0d28d (diff)
Merge #273
273: Add a test to ensure that we can parse each file r=matklad a=DJMcNab Note that this has a non-spurious failure in ra_analysis/src/mock_analysis. Probably fixes #195. If my understanding is correct, fixes #214 and fixes #225. Co-authored-by: DJMcNab <[email protected]>
Diffstat (limited to 'crates/ra_syntax/src/grammar/expressions.rs')
-rw-r--r--crates/ra_syntax/src/grammar/expressions.rs72
1 files changed, 39 insertions, 33 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