diff options
Diffstat (limited to 'src/grammar')
-rw-r--r-- | src/grammar/expressions/atom.rs | 4 | ||||
-rw-r--r-- | src/grammar/expressions/mod.rs | 47 | ||||
-rw-r--r-- | src/grammar/patterns.rs | 23 |
3 files changed, 59 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; | |||
6 | const EXPR_FIRST: TokenSet = LHS_FIRST; | 6 | const EXPR_FIRST: TokenSet = LHS_FIRST; |
7 | 7 | ||
8 | pub(super) fn expr(p: &mut Parser) -> BlockLike { | 8 | pub(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 | |||
13 | pub(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 | ||
13 | fn expr_no_struct(p: &mut Parser) { | 18 | fn 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)] |
32 | struct Restrictions { | 37 | struct Restrictions { |
33 | forbid_structs: bool | 38 | forbid_structs: bool, |
39 | prefer_stmt: bool, | ||
34 | } | 40 | } |
35 | 41 | ||
36 | enum Op { | 42 | enum 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. |
88 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | 94 | fn 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 | ||
181 | fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker { | 192 | fn 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 | } |
diff --git a/src/grammar/patterns.rs b/src/grammar/patterns.rs index f1d48b5fa..36ead7561 100644 --- a/src/grammar/patterns.rs +++ b/src/grammar/patterns.rs | |||
@@ -17,6 +17,7 @@ pub(super) fn pattern(p: &mut Parser) { | |||
17 | UNDERSCORE => placeholder_pat(p), | 17 | UNDERSCORE => placeholder_pat(p), |
18 | AMP => ref_pat(p), | 18 | AMP => ref_pat(p), |
19 | L_PAREN => tuple_pat(p), | 19 | L_PAREN => tuple_pat(p), |
20 | L_BRACK => slice_pat(p), | ||
20 | _ => p.err_and_bump("expected pattern"), | 21 | _ => p.err_and_bump("expected pattern"), |
21 | } | 22 | } |
22 | } | 23 | } |
@@ -128,6 +129,28 @@ fn tuple_pat(p: &mut Parser) { | |||
128 | m.complete(p, TUPLE_PAT); | 129 | m.complete(p, TUPLE_PAT); |
129 | } | 130 | } |
130 | 131 | ||
132 | // test slice_pat | ||
133 | // fn main() { | ||
134 | // let [a, b, ..] = []; | ||
135 | // } | ||
136 | fn slice_pat(p: &mut Parser) { | ||
137 | assert!(p.at(L_BRACK)); | ||
138 | let m = p.start(); | ||
139 | p.bump(); | ||
140 | while !p.at(EOF) && !p.at(R_BRACK) { | ||
141 | match p.current() { | ||
142 | DOTDOT => p.bump(), | ||
143 | _ => pattern(p), | ||
144 | } | ||
145 | if !p.at(R_BRACK) { | ||
146 | p.expect(COMMA); | ||
147 | } | ||
148 | } | ||
149 | p.expect(R_BRACK); | ||
150 | |||
151 | m.complete(p, SLICE_PAT); | ||
152 | } | ||
153 | |||
131 | // test bind_pat | 154 | // test bind_pat |
132 | // fn main() { | 155 | // fn main() { |
133 | // let a = (); | 156 | // let a = (); |