aboutsummaryrefslogtreecommitdiff
path: root/src/grammar/expressions
diff options
context:
space:
mode:
Diffstat (limited to 'src/grammar/expressions')
-rw-r--r--src/grammar/expressions/atom.rs4
-rw-r--r--src/grammar/expressions/mod.rs47
2 files changed, 36 insertions, 15 deletions
diff --git a/src/grammar/expressions/atom.rs b/src/grammar/expressions/atom.rs
index 524a69a8c..af9f47c5e 100644
--- a/src/grammar/expressions/atom.rs
+++ b/src/grammar/expressions/atom.rs
@@ -262,7 +262,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
262 expr_no_struct(p); 262 expr_no_struct(p);
263 } 263 }
264 p.expect(FAT_ARROW); 264 p.expect(FAT_ARROW);
265 let ret = expr(p); 265 let ret = expr_stmt(p);
266 m.complete(p, MATCH_ARM); 266 m.complete(p, MATCH_ARM);
267 ret 267 ret
268} 268}
@@ -295,7 +295,7 @@ pub(super) fn block_expr(p: &mut Parser) -> CompletedMarker {
295 // test pub_expr 295 // test pub_expr
296 // fn foo() { pub 92; } //FIXME 296 // fn foo() { pub 92; } //FIXME
297 items::MaybeItem::None => { 297 items::MaybeItem::None => {
298 let is_blocklike = expressions::expr(p) == BlockLike::Block; 298 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
299 if p.eat(SEMI) || (is_blocklike && !p.at(R_CURLY)) { 299 if p.eat(SEMI) || (is_blocklike && !p.at(R_CURLY)) {
300 m.complete(p, EXPR_STMT); 300 m.complete(p, EXPR_STMT);
301 } else { 301 } else {
diff --git a/src/grammar/expressions/mod.rs b/src/grammar/expressions/mod.rs
index ce709dbb2..dcbb1e2a8 100644
--- a/src/grammar/expressions/mod.rs
+++ b/src/grammar/expressions/mod.rs
@@ -6,12 +6,17 @@ pub(super) use self::atom::literal;
6const EXPR_FIRST: TokenSet = LHS_FIRST; 6const EXPR_FIRST: TokenSet = LHS_FIRST;
7 7
8pub(super) fn expr(p: &mut Parser) -> BlockLike { 8pub(super) fn expr(p: &mut Parser) -> BlockLike {
9 let r = Restrictions { forbid_structs: false }; 9 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
10 expr_bp(p, r, 1)
11}
12
13pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
14 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
10 expr_bp(p, r, 1) 15 expr_bp(p, r, 1)
11} 16}
12 17
13fn expr_no_struct(p: &mut Parser) { 18fn expr_no_struct(p: &mut Parser) {
14 let r = Restrictions { forbid_structs: true }; 19 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
15 expr_bp(p, r, 1); 20 expr_bp(p, r, 1);
16} 21}
17 22
@@ -30,7 +35,8 @@ pub(super) fn block(p: &mut Parser) {
30 35
31#[derive(Clone, Copy)] 36#[derive(Clone, Copy)]
32struct Restrictions { 37struct Restrictions {
33 forbid_structs: bool 38 forbid_structs: bool,
39 prefer_stmt: bool,
34} 40}
35 41
36enum Op { 42enum Op {
@@ -86,12 +92,18 @@ fn current_op(p: &Parser) -> (u8, Op) {
86 92
87// Parses expression with binding power of at least bp. 93// Parses expression with binding power of at least bp.
88fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { 94fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
89 let mut block: bool;
90 let mut lhs = match lhs(p, r) { 95 let mut lhs = match lhs(p, r) {
91 Some(lhs) => { 96 Some(lhs) => {
92 block = is_block(lhs.kind()); 97 // test stmt_bin_expr_ambiguity
98 // fn foo() {
99 // let _ = {1} & 2;
100 // {1} &2;
101 // }
102 if r.prefer_stmt && is_block(lhs.kind()) {
103 return BlockLike::Block;
104 }
93 lhs 105 lhs
94 }, 106 }
95 None => return BlockLike::NotBlock, 107 None => return BlockLike::NotBlock,
96 }; 108 };
97 109
@@ -101,7 +113,6 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
101 if op_bp < bp { 113 if op_bp < bp {
102 break; 114 break;
103 } 115 }
104 block = false;
105 let m = lhs.precede(p); 116 let m = lhs.precede(p);
106 match op { 117 match op {
107 Op::Simple => p.bump(), 118 Op::Simple => p.bump(),
@@ -112,7 +123,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
112 expr_bp(p, r, op_bp + 1); 123 expr_bp(p, r, op_bp + 1);
113 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); 124 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
114 } 125 }
115 if block { BlockLike::Block } else { BlockLike::NotBlock } 126 BlockLike::NotBlock
116} 127}
117 128
118// test no_semi_after_block 129// test no_semi_after_block
@@ -171,18 +182,27 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
171 } 182 }
172 _ => { 183 _ => {
173 let lhs = atom::atom_expr(p, r)?; 184 let lhs = atom::atom_expr(p, r)?;
174 return Some(postfix_expr(p, lhs)); 185 return Some(postfix_expr(p, r, lhs));
175 } 186 }
176 }; 187 };
177 expr_bp(p, r, 255); 188 expr_bp(p, r, 255);
178 Some(m.complete(p, kind)) 189 Some(m.complete(p, kind))
179} 190}
180 191
181fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker { 192fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker {
193 let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind());
182 loop { 194 loop {
183 lhs = match p.current() { 195 lhs = match p.current() {
184 L_PAREN => call_expr(p, lhs), 196 // test stmt_postfix_expr_ambiguity
185 L_BRACK => index_expr(p, lhs), 197 // fn foo() {
198 // match () {
199 // _ => {}
200 // () => {}
201 // [] => {}
202 // }
203 // }
204 L_PAREN if allow_calls => call_expr(p, lhs),
205 L_BRACK if allow_calls => index_expr(p, lhs),
186 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON { 206 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
187 method_call_expr(p, lhs) 207 method_call_expr(p, lhs)
188 } else { 208 } else {
@@ -199,7 +219,8 @@ fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker {
199 QUESTION => try_expr(p, lhs), 219 QUESTION => try_expr(p, lhs),
200 AS_KW => cast_expr(p, lhs), 220 AS_KW => cast_expr(p, lhs),
201 _ => break, 221 _ => break,
202 } 222 };
223 allow_calls = true
203 } 224 }
204 lhs 225 lhs
205} 226}