aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src/grammar/expressions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src/grammar/expressions.rs')
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs50
1 files changed, 41 insertions, 9 deletions
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 9b38b0a31..295577325 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -8,17 +8,20 @@ const EXPR_FIRST: TokenSet = LHS_FIRST;
8 8
9pub(super) fn expr(p: &mut Parser) -> BlockLike { 9pub(super) fn expr(p: &mut Parser) -> BlockLike {
10 let r = Restrictions { forbid_structs: false, prefer_stmt: false }; 10 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
11 expr_bp(p, r, 1).1 11 let mut dollar_lvl = 0;
12 expr_bp(p, r, 1, &mut dollar_lvl).1
12} 13}
13 14
14pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { 15pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
15 let r = Restrictions { forbid_structs: false, prefer_stmt: true }; 16 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
16 expr_bp(p, r, 1) 17 let mut dollar_lvl = 0;
18 expr_bp(p, r, 1, &mut dollar_lvl)
17} 19}
18 20
19fn expr_no_struct(p: &mut Parser) { 21fn expr_no_struct(p: &mut Parser) {
20 let r = Restrictions { forbid_structs: true, prefer_stmt: false }; 22 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
21 expr_bp(p, r, 1); 23 let mut dollar_lvl = 0;
24 expr_bp(p, r, 1, &mut dollar_lvl);
22} 25}
23 26
24// test block 27// test block
@@ -206,8 +209,23 @@ fn current_op(p: &Parser) -> (u8, Op) {
206} 209}
207 210
208// Parses expression with binding power of at least bp. 211// Parses expression with binding power of at least bp.
209fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) { 212fn expr_bp(
210 let mut lhs = match lhs(p, r) { 213 p: &mut Parser,
214 r: Restrictions,
215 mut bp: u8,
216 dollar_lvl: &mut usize,
217) -> (Option<CompletedMarker>, BlockLike) {
218 // `newly_dollar_open` is a flag indicated that dollar is just closed after lhs, e.g.
219 // `$1$ + a`
220 // We use this flag to skip handling it.
221 let mut newly_dollar_open = false;
222
223 if p.at_l_dollar() {
224 *dollar_lvl += p.eat_l_dollars();
225 newly_dollar_open = true;
226 }
227
228 let mut lhs = match lhs(p, r, dollar_lvl) {
211 Some((lhs, blocklike)) => { 229 Some((lhs, blocklike)) => {
212 // test stmt_bin_expr_ambiguity 230 // test stmt_bin_expr_ambiguity
213 // fn foo() { 231 // fn foo() {
@@ -223,6 +241,15 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>,
223 }; 241 };
224 242
225 loop { 243 loop {
244 if *dollar_lvl > 0 && p.at_r_dollar() {
245 *dollar_lvl -= p.eat_r_dollars(*dollar_lvl);
246 if !newly_dollar_open {
247 // We "pump" bp for make it highest priority
248 bp = 255;
249 }
250 newly_dollar_open = false;
251 }
252
226 let is_range = p.current() == DOTDOT || p.current() == DOTDOTEQ; 253 let is_range = p.current() == DOTDOT || p.current() == DOTDOTEQ;
227 let (op_bp, op) = current_op(p); 254 let (op_bp, op) = current_op(p);
228 if op_bp < bp { 255 if op_bp < bp {
@@ -235,7 +262,8 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>,
235 p.bump_compound(kind, n); 262 p.bump_compound(kind, n);
236 } 263 }
237 } 264 }
238 expr_bp(p, r, op_bp + 1); 265
266 expr_bp(p, r, op_bp + 1, dollar_lvl);
239 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); 267 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
240 } 268 }
241 (Some(lhs), BlockLike::NotBlock) 269 (Some(lhs), BlockLike::NotBlock)
@@ -244,7 +272,11 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>,
244const LHS_FIRST: TokenSet = 272const LHS_FIRST: TokenSet =
245 atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]); 273 atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]);
246 274
247fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { 275fn lhs(
276 p: &mut Parser,
277 r: Restrictions,
278 dollar_lvl: &mut usize,
279) -> Option<(CompletedMarker, BlockLike)> {
248 let m; 280 let m;
249 let kind = match p.current() { 281 let kind = match p.current() {
250 // test ref_expr 282 // test ref_expr
@@ -275,7 +307,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
275 m = p.start(); 307 m = p.start();
276 p.bump(); 308 p.bump();
277 if p.at_ts(EXPR_FIRST) { 309 if p.at_ts(EXPR_FIRST) {
278 expr_bp(p, r, 2); 310 expr_bp(p, r, 2, dollar_lvl);
279 } 311 }
280 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); 312 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
281 } 313 }
@@ -287,7 +319,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
287 )); 319 ));
288 } 320 }
289 }; 321 };
290 expr_bp(p, r, 255); 322 expr_bp(p, r, 255, dollar_lvl);
291 Some((m.complete(p, kind), BlockLike::NotBlock)) 323 Some((m.complete(p, kind), BlockLike::NotBlock))
292} 324}
293 325