diff options
Diffstat (limited to 'src/grammar/expressions')
-rw-r--r-- | src/grammar/expressions/atom.rs | 24 | ||||
-rw-r--r-- | src/grammar/expressions/mod.rs | 33 |
2 files changed, 45 insertions, 12 deletions
diff --git a/src/grammar/expressions/atom.rs b/src/grammar/expressions/atom.rs index e4f681c17..524a69a8c 100644 --- a/src/grammar/expressions/atom.rs +++ b/src/grammar/expressions/atom.rs | |||
@@ -133,7 +133,7 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker { | |||
133 | if fn_ret_type(p) { | 133 | if fn_ret_type(p) { |
134 | block(p); | 134 | block(p); |
135 | } else { | 135 | } else { |
136 | expr(p) | 136 | expr(p); |
137 | } | 137 | } |
138 | m.complete(p, LAMBDA_EXPR) | 138 | m.complete(p, LAMBDA_EXPR) |
139 | } | 139 | } |
@@ -225,8 +225,17 @@ fn match_expr(p: &mut Parser) -> CompletedMarker { | |||
225 | expr_no_struct(p); | 225 | expr_no_struct(p); |
226 | p.eat(L_CURLY); | 226 | p.eat(L_CURLY); |
227 | while !p.at(EOF) && !p.at(R_CURLY) { | 227 | while !p.at(EOF) && !p.at(R_CURLY) { |
228 | match_arm(p); | 228 | // test match_arms_commas |
229 | if !p.at(R_CURLY) { | 229 | // fn foo() { |
230 | // match () { | ||
231 | // _ => (), | ||
232 | // _ => {} | ||
233 | // _ => () | ||
234 | // } | ||
235 | // } | ||
236 | if match_arm(p).is_block() { | ||
237 | p.eat(COMMA); | ||
238 | } else if !p.at(R_CURLY) { | ||
230 | p.expect(COMMA); | 239 | p.expect(COMMA); |
231 | } | 240 | } |
232 | } | 241 | } |
@@ -241,7 +250,7 @@ fn match_expr(p: &mut Parser) -> CompletedMarker { | |||
241 | // X | Y if Z => (), | 250 | // X | Y if Z => (), |
242 | // }; | 251 | // }; |
243 | // } | 252 | // } |
244 | fn match_arm(p: &mut Parser) { | 253 | fn match_arm(p: &mut Parser) -> BlockLike { |
245 | let m = p.start(); | 254 | let m = p.start(); |
246 | loop { | 255 | loop { |
247 | patterns::pattern(p); | 256 | patterns::pattern(p); |
@@ -253,8 +262,9 @@ fn match_arm(p: &mut Parser) { | |||
253 | expr_no_struct(p); | 262 | expr_no_struct(p); |
254 | } | 263 | } |
255 | p.expect(FAT_ARROW); | 264 | p.expect(FAT_ARROW); |
256 | expr(p); | 265 | let ret = expr(p); |
257 | m.complete(p, MATCH_ARM); | 266 | m.complete(p, MATCH_ARM); |
267 | ret | ||
258 | } | 268 | } |
259 | 269 | ||
260 | // test block_expr | 270 | // test block_expr |
@@ -285,8 +295,8 @@ pub(super) fn block_expr(p: &mut Parser) -> CompletedMarker { | |||
285 | // test pub_expr | 295 | // test pub_expr |
286 | // fn foo() { pub 92; } //FIXME | 296 | // fn foo() { pub 92; } //FIXME |
287 | items::MaybeItem::None => { | 297 | items::MaybeItem::None => { |
288 | expressions::expr(p); | 298 | let is_blocklike = expressions::expr(p) == BlockLike::Block; |
289 | if p.eat(SEMI) { | 299 | if p.eat(SEMI) || (is_blocklike && !p.at(R_CURLY)) { |
290 | m.complete(p, EXPR_STMT); | 300 | m.complete(p, EXPR_STMT); |
291 | } else { | 301 | } else { |
292 | m.abandon(p); | 302 | m.abandon(p); |
diff --git a/src/grammar/expressions/mod.rs b/src/grammar/expressions/mod.rs index 55e965ff4..ce709dbb2 100644 --- a/src/grammar/expressions/mod.rs +++ b/src/grammar/expressions/mod.rs | |||
@@ -5,14 +5,14 @@ pub(super) use self::atom::literal; | |||
5 | 5 | ||
6 | const EXPR_FIRST: TokenSet = LHS_FIRST; | 6 | const EXPR_FIRST: TokenSet = LHS_FIRST; |
7 | 7 | ||
8 | pub(super) fn expr(p: &mut Parser) { | 8 | pub(super) fn expr(p: &mut Parser) -> BlockLike { |
9 | let r = Restrictions { forbid_structs: false }; | 9 | let r = Restrictions { forbid_structs: false }; |
10 | expr_bp(p, r, 1) | 10 | expr_bp(p, r, 1) |
11 | } | 11 | } |
12 | 12 | ||
13 | fn expr_no_struct(p: &mut Parser) { | 13 | fn expr_no_struct(p: &mut Parser) { |
14 | let r = Restrictions { forbid_structs: true }; | 14 | let r = Restrictions { forbid_structs: true }; |
15 | expr_bp(p, r, 1) | 15 | expr_bp(p, r, 1); |
16 | } | 16 | } |
17 | 17 | ||
18 | // test block | 18 | // test block |
@@ -85,10 +85,14 @@ fn current_op(p: &Parser) -> (u8, Op) { | |||
85 | } | 85 | } |
86 | 86 | ||
87 | // Parses expression with binding power of at least bp. | 87 | // Parses expression with binding power of at least bp. |
88 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) { | 88 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { |
89 | let mut block: bool; | ||
89 | let mut lhs = match lhs(p, r) { | 90 | let mut lhs = match lhs(p, r) { |
90 | Some(lhs) => lhs, | 91 | Some(lhs) => { |
91 | None => return, | 92 | block = is_block(lhs.kind()); |
93 | lhs | ||
94 | }, | ||
95 | None => return BlockLike::NotBlock, | ||
92 | }; | 96 | }; |
93 | 97 | ||
94 | loop { | 98 | loop { |
@@ -97,6 +101,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) { | |||
97 | if op_bp < bp { | 101 | if op_bp < bp { |
98 | break; | 102 | break; |
99 | } | 103 | } |
104 | block = false; | ||
100 | let m = lhs.precede(p); | 105 | let m = lhs.precede(p); |
101 | match op { | 106 | match op { |
102 | Op::Simple => p.bump(), | 107 | Op::Simple => p.bump(), |
@@ -107,6 +112,24 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) { | |||
107 | expr_bp(p, r, op_bp + 1); | 112 | expr_bp(p, r, op_bp + 1); |
108 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | 113 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); |
109 | } | 114 | } |
115 | if block { BlockLike::Block } else { BlockLike::NotBlock } | ||
116 | } | ||
117 | |||
118 | // test no_semi_after_block | ||
119 | // fn foo() { | ||
120 | // if true {} | ||
121 | // loop {} | ||
122 | // match () {} | ||
123 | // while true {} | ||
124 | // for _ in () {} | ||
125 | // {} | ||
126 | // {} | ||
127 | // } | ||
128 | fn is_block(kind: SyntaxKind) -> bool { | ||
129 | match kind { | ||
130 | IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => true, | ||
131 | _ => false, | ||
132 | } | ||
110 | } | 133 | } |
111 | 134 | ||
112 | const LHS_FIRST: TokenSet = | 135 | const LHS_FIRST: TokenSet = |