aboutsummaryrefslogtreecommitdiff
path: root/src/grammar
diff options
context:
space:
mode:
Diffstat (limited to 'src/grammar')
-rw-r--r--src/grammar/expressions/atom.rs24
-rw-r--r--src/grammar/expressions/mod.rs33
-rw-r--r--src/grammar/mod.rs5
3 files changed, 50 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// }
244fn match_arm(p: &mut Parser) { 253fn 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
6const EXPR_FIRST: TokenSet = LHS_FIRST; 6const EXPR_FIRST: TokenSet = LHS_FIRST;
7 7
8pub(super) fn expr(p: &mut Parser) { 8pub(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
13fn expr_no_struct(p: &mut Parser) { 13fn 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.
88fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) { 88fn 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// }
128fn 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
112const LHS_FIRST: TokenSet = 135const LHS_FIRST: TokenSet =
diff --git a/src/grammar/mod.rs b/src/grammar/mod.rs
index 1b997d861..b6da0d013 100644
--- a/src/grammar/mod.rs
+++ b/src/grammar/mod.rs
@@ -44,11 +44,16 @@ pub(crate) fn file(p: &mut Parser) {
44} 44}
45 45
46 46
47#[derive(Clone, Copy, PartialEq, Eq)]
47enum BlockLike { 48enum BlockLike {
48 Block, 49 Block,
49 NotBlock, 50 NotBlock,
50} 51}
51 52
53impl BlockLike {
54 fn is_block(self) -> bool { self == BlockLike::Block }
55}
56
52fn visibility(p: &mut Parser) { 57fn visibility(p: &mut Parser) {
53 if p.at(PUB_KW) { 58 if p.at(PUB_KW) {
54 let vis = p.start(); 59 let vis = p.start();