diff options
Diffstat (limited to 'crates/ra_parser/src/grammar/expressions.rs')
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 245 |
1 files changed, 115 insertions, 130 deletions
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 30036eb46..1dd9a586c 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -14,20 +14,17 @@ const EXPR_FIRST: TokenSet = LHS_FIRST; | |||
14 | 14 | ||
15 | pub(super) fn expr(p: &mut Parser) -> BlockLike { | 15 | pub(super) fn expr(p: &mut Parser) -> BlockLike { |
16 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; | 16 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; |
17 | let mut dollar_lvl = 0; | 17 | expr_bp(p, r, 1).1 |
18 | expr_bp(p, r, 1, &mut dollar_lvl).1 | ||
19 | } | 18 | } |
20 | 19 | ||
21 | pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { | 20 | pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { |
22 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; | 21 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; |
23 | let mut dollar_lvl = 0; | 22 | expr_bp(p, r, 1) |
24 | expr_bp(p, r, 1, &mut dollar_lvl) | ||
25 | } | 23 | } |
26 | 24 | ||
27 | fn expr_no_struct(p: &mut Parser) { | 25 | fn expr_no_struct(p: &mut Parser) { |
28 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; | 26 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; |
29 | let mut dollar_lvl = 0; | 27 | expr_bp(p, r, 1); |
30 | expr_bp(p, r, 1, &mut dollar_lvl); | ||
31 | } | 28 | } |
32 | 29 | ||
33 | // test block | 30 | // test block |
@@ -212,72 +209,53 @@ struct Restrictions { | |||
212 | prefer_stmt: bool, | 209 | prefer_stmt: bool, |
213 | } | 210 | } |
214 | 211 | ||
215 | enum Op { | 212 | /// Binding powers of operators for a Pratt parser. |
216 | Simple, | 213 | /// |
217 | Composite(SyntaxKind, u8), | 214 | /// See https://www.oilshell.org/blog/2016/11/03.html |
218 | } | 215 | #[rustfmt::skip] |
219 | 216 | fn current_op(p: &Parser) -> (u8, SyntaxKind) { | |
220 | fn current_op(p: &Parser) -> (u8, Op) { | 217 | const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]); |
221 | if let Some(t) = p.current3() { | 218 | match p.current() { |
222 | match t { | 219 | T![|] if p.at(T![||]) => (3, T![||]), |
223 | (T![<], T![<], T![=]) => return (1, Op::Composite(T![<<=], 3)), | 220 | T![|] if p.at(T![|=]) => (1, T![|=]), |
224 | (T![>], T![>], T![=]) => return (1, Op::Composite(T![>>=], 3)), | 221 | T![|] => (6, T![|]), |
225 | _ => (), | 222 | T![>] if p.at(T![>>=]) => (1, T![>>=]), |
226 | } | 223 | T![>] if p.at(T![>>]) => (9, T![>>]), |
227 | } | 224 | T![>] if p.at(T![>=]) => (5, T![>=]), |
228 | 225 | T![>] => (5, T![>]), | |
229 | if let Some(t) = p.current2() { | 226 | T![=] if p.at(T![=>]) => NOT_AN_OP, |
230 | match t { | 227 | T![=] if p.at(T![==]) => (5, T![==]), |
231 | (T![+], T![=]) => return (1, Op::Composite(T![+=], 2)), | 228 | T![=] => (1, T![=]), |
232 | (T![-], T![=]) => return (1, Op::Composite(T![-=], 2)), | 229 | T![<] if p.at(T![<=]) => (5, T![<=]), |
233 | (T![*], T![=]) => return (1, Op::Composite(T![*=], 2)), | 230 | T![<] if p.at(T![<<=]) => (1, T![<<=]), |
234 | (T![%], T![=]) => return (1, Op::Composite(T![%=], 2)), | 231 | T![<] if p.at(T![<<]) => (9, T![<<]), |
235 | (T![/], T![=]) => return (1, Op::Composite(T![/=], 2)), | 232 | T![<] => (5, T![<]), |
236 | (T![|], T![=]) => return (1, Op::Composite(T![|=], 2)), | 233 | T![+] if p.at(T![+=]) => (1, T![+=]), |
237 | (T![&], T![=]) => return (1, Op::Composite(T![&=], 2)), | 234 | T![+] => (10, T![+]), |
238 | (T![^], T![=]) => return (1, Op::Composite(T![^=], 2)), | 235 | T![^] if p.at(T![^=]) => (1, T![^=]), |
239 | (T![|], T![|]) => return (3, Op::Composite(T![||], 2)), | 236 | T![^] => (7, T![^]), |
240 | (T![&], T![&]) => return (4, Op::Composite(T![&&], 2)), | 237 | T![%] if p.at(T![%=]) => (1, T![%=]), |
241 | (T![<], T![=]) => return (5, Op::Composite(T![<=], 2)), | 238 | T![%] => (11, T![%]), |
242 | (T![>], T![=]) => return (5, Op::Composite(T![>=], 2)), | 239 | T![&] if p.at(T![&=]) => (1, T![&=]), |
243 | (T![<], T![<]) => return (9, Op::Composite(T![<<], 2)), | 240 | T![&] if p.at(T![&&]) => (4, T![&&]), |
244 | (T![>], T![>]) => return (9, Op::Composite(T![>>], 2)), | 241 | T![&] => (8, T![&]), |
245 | _ => (), | 242 | T![/] if p.at(T![/=]) => (1, T![/=]), |
246 | } | 243 | T![/] => (11, T![/]), |
244 | T![*] if p.at(T![*=]) => (1, T![*=]), | ||
245 | T![*] => (11, T![*]), | ||
246 | T![.] if p.at(T![..=]) => (2, T![..=]), | ||
247 | T![.] if p.at(T![..]) => (2, T![..]), | ||
248 | T![!] if p.at(T![!=]) => (5, T![!=]), | ||
249 | T![-] if p.at(T![-=]) => (1, T![-=]), | ||
250 | T![-] => (10, T![-]), | ||
251 | |||
252 | _ => NOT_AN_OP | ||
247 | } | 253 | } |
248 | |||
249 | let bp = match p.current() { | ||
250 | T![=] => 1, | ||
251 | T![..] | T![..=] => 2, | ||
252 | T![==] | T![!=] | T![<] | T![>] => 5, | ||
253 | T![|] => 6, | ||
254 | T![^] => 7, | ||
255 | T![&] => 8, | ||
256 | T![-] | T![+] => 10, | ||
257 | T![*] | T![/] | T![%] => 11, | ||
258 | _ => 0, | ||
259 | }; | ||
260 | (bp, Op::Simple) | ||
261 | } | 254 | } |
262 | 255 | ||
263 | // Parses expression with binding power of at least bp. | 256 | // Parses expression with binding power of at least bp. |
264 | fn expr_bp( | 257 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) { |
265 | p: &mut Parser, | 258 | let mut lhs = match lhs(p, r) { |
266 | r: Restrictions, | ||
267 | mut bp: u8, | ||
268 | dollar_lvl: &mut usize, | ||
269 | ) -> (Option<CompletedMarker>, BlockLike) { | ||
270 | // `newly_dollar_open` is a flag indicated that dollar is just closed after lhs, e.g. | ||
271 | // `$1$ + a` | ||
272 | // We use this flag to skip handling it. | ||
273 | let mut newly_dollar_open = if p.at_l_dollar() { | ||
274 | *dollar_lvl += p.eat_l_dollars(); | ||
275 | true | ||
276 | } else { | ||
277 | false | ||
278 | }; | ||
279 | |||
280 | let mut lhs = match lhs(p, r, dollar_lvl) { | ||
281 | Some((lhs, blocklike)) => { | 259 | Some((lhs, blocklike)) => { |
282 | // test stmt_bin_expr_ambiguity | 260 | // test stmt_bin_expr_ambiguity |
283 | // fn foo() { | 261 | // fn foo() { |
@@ -293,42 +271,23 @@ fn expr_bp( | |||
293 | }; | 271 | }; |
294 | 272 | ||
295 | loop { | 273 | loop { |
296 | if *dollar_lvl > 0 && p.at_r_dollar() { | ||
297 | *dollar_lvl -= p.eat_r_dollars(*dollar_lvl); | ||
298 | if !newly_dollar_open { | ||
299 | // We "pump" bp for make it highest priority | ||
300 | bp = 255; | ||
301 | } | ||
302 | newly_dollar_open = false; | ||
303 | } | ||
304 | |||
305 | let is_range = p.at(T![..]) || p.at(T![..=]); | 274 | let is_range = p.at(T![..]) || p.at(T![..=]); |
306 | let (op_bp, op) = current_op(p); | 275 | let (op_bp, op) = current_op(p); |
307 | if op_bp < bp { | 276 | if op_bp < bp { |
308 | break; | 277 | break; |
309 | } | 278 | } |
310 | let m = lhs.precede(p); | 279 | let m = lhs.precede(p); |
311 | match op { | 280 | p.bump(op); |
312 | Op::Simple => p.bump_any(), | ||
313 | Op::Composite(kind, n) => { | ||
314 | p.bump_compound(kind, n); | ||
315 | } | ||
316 | } | ||
317 | 281 | ||
318 | expr_bp(p, r, op_bp + 1, dollar_lvl); | 282 | expr_bp(p, r, op_bp + 1); |
319 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | 283 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); |
320 | } | 284 | } |
321 | (Some(lhs), BlockLike::NotBlock) | 285 | (Some(lhs), BlockLike::NotBlock) |
322 | } | 286 | } |
323 | 287 | ||
324 | const LHS_FIRST: TokenSet = | 288 | const LHS_FIRST: TokenSet = atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOT, MINUS]); |
325 | atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]); | ||
326 | 289 | ||
327 | fn lhs( | 290 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { |
328 | p: &mut Parser, | ||
329 | r: Restrictions, | ||
330 | dollar_lvl: &mut usize, | ||
331 | ) -> Option<(CompletedMarker, BlockLike)> { | ||
332 | let m; | 291 | let m; |
333 | let kind = match p.current() { | 292 | let kind = match p.current() { |
334 | // test ref_expr | 293 | // test ref_expr |
@@ -353,17 +312,20 @@ fn lhs( | |||
353 | p.bump_any(); | 312 | p.bump_any(); |
354 | PREFIX_EXPR | 313 | PREFIX_EXPR |
355 | } | 314 | } |
356 | // test full_range_expr | ||
357 | // fn foo() { xs[..]; } | ||
358 | T![..] | T![..=] => { | ||
359 | m = p.start(); | ||
360 | p.bump_any(); | ||
361 | if p.at_ts(EXPR_FIRST) { | ||
362 | expr_bp(p, r, 2, dollar_lvl); | ||
363 | } | ||
364 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | ||
365 | } | ||
366 | _ => { | 315 | _ => { |
316 | // test full_range_expr | ||
317 | // fn foo() { xs[..]; } | ||
318 | for &op in [T![..=], T![..]].iter() { | ||
319 | if p.at(op) { | ||
320 | m = p.start(); | ||
321 | p.bump(op); | ||
322 | if p.at_ts(EXPR_FIRST) { | ||
323 | expr_bp(p, r, 2); | ||
324 | } | ||
325 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | ||
326 | } | ||
327 | } | ||
328 | |||
367 | // test expression_after_block | 329 | // test expression_after_block |
368 | // fn foo() { | 330 | // fn foo() { |
369 | // let mut p = F{x: 5}; | 331 | // let mut p = F{x: 5}; |
@@ -374,7 +336,7 @@ fn lhs( | |||
374 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); | 336 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); |
375 | } | 337 | } |
376 | }; | 338 | }; |
377 | expr_bp(p, r, 255, dollar_lvl); | 339 | expr_bp(p, r, 255); |
378 | Some((m.complete(p, kind), BlockLike::NotBlock)) | 340 | Some((m.complete(p, kind), BlockLike::NotBlock)) |
379 | } | 341 | } |
380 | 342 | ||
@@ -399,29 +361,13 @@ fn postfix_expr( | |||
399 | // } | 361 | // } |
400 | T!['('] if allow_calls => call_expr(p, lhs), | 362 | T!['('] if allow_calls => call_expr(p, lhs), |
401 | T!['['] if allow_calls => index_expr(p, lhs), | 363 | T!['['] if allow_calls => index_expr(p, lhs), |
402 | T![.] if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::]) => { | 364 | T![.] => match postfix_dot_expr(p, lhs) { |
403 | method_call_expr(p, lhs) | 365 | Ok(it) => it, |
404 | } | 366 | Err(it) => { |
405 | T![.] if p.nth(1) == AWAIT_KW => { | 367 | lhs = it; |
406 | // test await_expr | 368 | break; |
407 | // fn foo() { | 369 | } |
408 | // x.await; | 370 | }, |
409 | // x.0.await; | ||
410 | // x.0().await?.hello(); | ||
411 | // } | ||
412 | let m = lhs.precede(p); | ||
413 | p.bump_any(); | ||
414 | p.bump_any(); | ||
415 | m.complete(p, AWAIT_EXPR) | ||
416 | } | ||
417 | T![.] => field_expr(p, lhs), | ||
418 | // test postfix_range | ||
419 | // fn foo() { let x = 1..; } | ||
420 | T![..] | T![..=] if !EXPR_FIRST.contains(p.nth(1)) => { | ||
421 | let m = lhs.precede(p); | ||
422 | p.bump_any(); | ||
423 | m.complete(p, RANGE_EXPR) | ||
424 | } | ||
425 | T![?] => try_expr(p, lhs), | 371 | T![?] => try_expr(p, lhs), |
426 | T![as] => cast_expr(p, lhs), | 372 | T![as] => cast_expr(p, lhs), |
427 | _ => break, | 373 | _ => break, |
@@ -429,7 +375,46 @@ fn postfix_expr( | |||
429 | allow_calls = true; | 375 | allow_calls = true; |
430 | block_like = BlockLike::NotBlock; | 376 | block_like = BlockLike::NotBlock; |
431 | } | 377 | } |
432 | (lhs, block_like) | 378 | return (lhs, block_like); |
379 | |||
380 | fn postfix_dot_expr( | ||
381 | p: &mut Parser, | ||
382 | lhs: CompletedMarker, | ||
383 | ) -> Result<CompletedMarker, CompletedMarker> { | ||
384 | assert!(p.at(T![.])); | ||
385 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { | ||
386 | return Ok(method_call_expr(p, lhs)); | ||
387 | } | ||
388 | |||
389 | // test await_expr | ||
390 | // fn foo() { | ||
391 | // x.await; | ||
392 | // x.0.await; | ||
393 | // x.0().await?.hello(); | ||
394 | // } | ||
395 | if p.nth(1) == T![await] { | ||
396 | let m = lhs.precede(p); | ||
397 | p.bump(T![.]); | ||
398 | p.bump(T![await]); | ||
399 | return Ok(m.complete(p, AWAIT_EXPR)); | ||
400 | } | ||
401 | |||
402 | // test postfix_range | ||
403 | // fn foo() { let x = 1..; } | ||
404 | for &(op, la) in [(T![..=], 3), (T![..], 2)].iter() { | ||
405 | if p.at(op) { | ||
406 | return if EXPR_FIRST.contains(p.nth(la)) { | ||
407 | Err(lhs) | ||
408 | } else { | ||
409 | let m = lhs.precede(p); | ||
410 | p.bump(op); | ||
411 | Ok(m.complete(p, RANGE_EXPR)) | ||
412 | }; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | Ok(field_expr(p, lhs)) | ||
417 | } | ||
433 | } | 418 | } |
434 | 419 | ||
435 | // test call_expr | 420 | // test call_expr |
@@ -465,7 +450,7 @@ fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
465 | // y.bar::<T>(1, 2,); | 450 | // y.bar::<T>(1, 2,); |
466 | // } | 451 | // } |
467 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 452 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
468 | assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::])); | 453 | assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); |
469 | let m = lhs.precede(p); | 454 | let m = lhs.precede(p); |
470 | p.bump_any(); | 455 | p.bump_any(); |
471 | name_ref(p); | 456 | name_ref(p); |
@@ -567,7 +552,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { | |||
567 | record_field_list(p); | 552 | record_field_list(p); |
568 | (m.complete(p, RECORD_LIT), BlockLike::NotBlock) | 553 | (m.complete(p, RECORD_LIT), BlockLike::NotBlock) |
569 | } | 554 | } |
570 | T![!] => { | 555 | T![!] if !p.at(T![!=]) => { |
571 | let block_like = items::macro_call_after_excl(p); | 556 | let block_like = items::macro_call_after_excl(p); |
572 | (m.complete(p, MACRO_CALL), block_like) | 557 | (m.complete(p, MACRO_CALL), block_like) |
573 | } | 558 | } |
@@ -601,8 +586,8 @@ pub(crate) fn record_field_list(p: &mut Parser) { | |||
601 | } | 586 | } |
602 | m.complete(p, RECORD_FIELD); | 587 | m.complete(p, RECORD_FIELD); |
603 | } | 588 | } |
604 | T![..] => { | 589 | T![.] if p.at(T![..]) => { |
605 | p.bump_any(); | 590 | p.bump(T![..]); |
606 | expr(p); | 591 | expr(p); |
607 | } | 592 | } |
608 | T!['{'] => error_block(p, "expected a field"), | 593 | T!['{'] => error_block(p, "expected a field"), |