aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grammar/expressions/atom.rs24
-rw-r--r--src/grammar/expressions/mod.rs33
-rw-r--r--src/grammar/mod.rs5
-rw-r--r--src/parser_api.rs9
-rw-r--r--tests/data/parser/inline/0085_match_arms_commas.rs7
-rw-r--r--tests/data/parser/inline/0085_match_arms_commas.txt57
-rw-r--r--tests/data/parser/inline/0086_no_semi_after_block.rs9
-rw-r--r--tests/data/parser/inline/0086_no_semi_after_block.txt82
8 files changed, 212 insertions, 14 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();
diff --git a/src/parser_api.rs b/src/parser_api.rs
index c739b1321..58002a8fc 100644
--- a/src/parser_api.rs
+++ b/src/parser_api.rs
@@ -6,6 +6,7 @@ use {
6 6
7#[derive(Clone, Copy)] 7#[derive(Clone, Copy)]
8pub(crate) struct TokenSet(pub(crate) u128); 8pub(crate) struct TokenSet(pub(crate) u128);
9
9fn mask(kind: SyntaxKind) -> u128 { 10fn mask(kind: SyntaxKind) -> u128 {
10 1u128 << (kind as usize) 11 1u128 << (kind as usize)
11} 12}
@@ -154,7 +155,7 @@ impl Marker {
154 pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { 155 pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
155 self.bomb.defuse(); 156 self.bomb.defuse();
156 p.0.complete(self.pos, kind); 157 p.0.complete(self.pos, kind);
157 CompletedMarker(self.pos) 158 CompletedMarker(self.pos, kind)
158 } 159 }
159 160
160 /// Abandons the syntax tree node. All its children 161 /// Abandons the syntax tree node. All its children
@@ -165,7 +166,7 @@ impl Marker {
165 } 166 }
166} 167}
167 168
168pub(crate) struct CompletedMarker(u32); 169pub(crate) struct CompletedMarker(u32, SyntaxKind);
169 170
170impl CompletedMarker { 171impl CompletedMarker {
171 /// This one is tricky :-) 172 /// This one is tricky :-)
@@ -178,4 +179,8 @@ impl CompletedMarker {
178 pub(crate) fn precede(self, p: &mut Parser) -> Marker { 179 pub(crate) fn precede(self, p: &mut Parser) -> Marker {
179 Marker::new(p.0.precede(self.0)) 180 Marker::new(p.0.precede(self.0))
180 } 181 }
182
183 pub(crate) fn kind(&self) -> SyntaxKind {
184 self.1
185 }
181} 186}
diff --git a/tests/data/parser/inline/0085_match_arms_commas.rs b/tests/data/parser/inline/0085_match_arms_commas.rs
new file mode 100644
index 000000000..1f25d577a
--- /dev/null
+++ b/tests/data/parser/inline/0085_match_arms_commas.rs
@@ -0,0 +1,7 @@
1fn foo() {
2 match () {
3 _ => (),
4 _ => {}
5 _ => ()
6 }
7}
diff --git a/tests/data/parser/inline/0085_match_arms_commas.txt b/tests/data/parser/inline/0085_match_arms_commas.txt
new file mode 100644
index 000000000..6dfc6c9dd
--- /dev/null
+++ b/tests/data/parser/inline/0085_match_arms_commas.txt
@@ -0,0 +1,57 @@
1FILE@[0; 83)
2 FN_ITEM@[0; 82)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 82)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 MATCH_EXPR@[15; 80)
15 MATCH_KW@[15; 20)
16 WHITESPACE@[20; 21)
17 TUPLE_EXPR@[21; 23)
18 L_PAREN@[21; 22)
19 R_PAREN@[22; 23)
20 WHITESPACE@[23; 24)
21 L_CURLY@[24; 25)
22 WHITESPACE@[25; 34)
23 MATCH_ARM@[34; 41)
24 PLACEHOLDER_PAT@[34; 35)
25 UNDERSCORE@[34; 35)
26 WHITESPACE@[35; 36)
27 FAT_ARROW@[36; 38)
28 WHITESPACE@[38; 39)
29 TUPLE_EXPR@[39; 41)
30 L_PAREN@[39; 40)
31 R_PAREN@[40; 41)
32 COMMA@[41; 42)
33 WHITESPACE@[42; 51)
34 MATCH_ARM@[51; 58)
35 PLACEHOLDER_PAT@[51; 52)
36 UNDERSCORE@[51; 52)
37 WHITESPACE@[52; 53)
38 FAT_ARROW@[53; 55)
39 WHITESPACE@[55; 56)
40 BLOCK_EXPR@[56; 58)
41 L_CURLY@[56; 57)
42 R_CURLY@[57; 58)
43 WHITESPACE@[58; 67)
44 MATCH_ARM@[67; 74)
45 PLACEHOLDER_PAT@[67; 68)
46 UNDERSCORE@[67; 68)
47 WHITESPACE@[68; 69)
48 FAT_ARROW@[69; 71)
49 WHITESPACE@[71; 72)
50 TUPLE_EXPR@[72; 74)
51 L_PAREN@[72; 73)
52 R_PAREN@[73; 74)
53 WHITESPACE@[74; 79)
54 R_CURLY@[79; 80)
55 WHITESPACE@[80; 81)
56 R_CURLY@[81; 82)
57 WHITESPACE@[82; 83)
diff --git a/tests/data/parser/inline/0086_no_semi_after_block.rs b/tests/data/parser/inline/0086_no_semi_after_block.rs
new file mode 100644
index 000000000..d769da43d
--- /dev/null
+++ b/tests/data/parser/inline/0086_no_semi_after_block.rs
@@ -0,0 +1,9 @@
1fn foo() {
2 if true {}
3 loop {}
4 match () {}
5 while true {}
6 for _ in () {}
7 {}
8 {}
9}
diff --git a/tests/data/parser/inline/0086_no_semi_after_block.txt b/tests/data/parser/inline/0086_no_semi_after_block.txt
new file mode 100644
index 000000000..dd05a8a9f
--- /dev/null
+++ b/tests/data/parser/inline/0086_no_semi_after_block.txt
@@ -0,0 +1,82 @@
1FILE@[0; 107)
2 FN_ITEM@[0; 106)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 106)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 25)
15 IF_EXPR@[15; 25)
16 IF_KW@[15; 17)
17 WHITESPACE@[17; 18)
18 LITERAL@[18; 22)
19 TRUE_KW@[18; 22)
20 WHITESPACE@[22; 23)
21 BLOCK_EXPR@[23; 25)
22 L_CURLY@[23; 24)
23 R_CURLY@[24; 25)
24 WHITESPACE@[25; 30)
25 EXPR_STMT@[30; 37)
26 LOOP_EXPR@[30; 37)
27 LOOP_KW@[30; 34)
28 WHITESPACE@[34; 35)
29 BLOCK_EXPR@[35; 37)
30 L_CURLY@[35; 36)
31 R_CURLY@[36; 37)
32 WHITESPACE@[37; 42)
33 EXPR_STMT@[42; 53)
34 MATCH_EXPR@[42; 53)
35 MATCH_KW@[42; 47)
36 WHITESPACE@[47; 48)
37 TUPLE_EXPR@[48; 50)
38 L_PAREN@[48; 49)
39 R_PAREN@[49; 50)
40 WHITESPACE@[50; 51)
41 L_CURLY@[51; 52)
42 R_CURLY@[52; 53)
43 WHITESPACE@[53; 58)
44 EXPR_STMT@[58; 71)
45 WHILE_EXPR@[58; 71)
46 WHILE_KW@[58; 63)
47 WHITESPACE@[63; 64)
48 LITERAL@[64; 68)
49 TRUE_KW@[64; 68)
50 WHITESPACE@[68; 69)
51 BLOCK_EXPR@[69; 71)
52 L_CURLY@[69; 70)
53 R_CURLY@[70; 71)
54 WHITESPACE@[71; 76)
55 EXPR_STMT@[76; 90)
56 FOR_EXPR@[76; 90)
57 FOR_KW@[76; 79)
58 WHITESPACE@[79; 80)
59 PLACEHOLDER_PAT@[80; 81)
60 UNDERSCORE@[80; 81)
61 WHITESPACE@[81; 82)
62 IN_KW@[82; 84)
63 WHITESPACE@[84; 85)
64 TUPLE_EXPR@[85; 87)
65 L_PAREN@[85; 86)
66 R_PAREN@[86; 87)
67 WHITESPACE@[87; 88)
68 BLOCK_EXPR@[88; 90)
69 L_CURLY@[88; 89)
70 R_CURLY@[89; 90)
71 WHITESPACE@[90; 95)
72 EXPR_STMT@[95; 97)
73 BLOCK_EXPR@[95; 97)
74 L_CURLY@[95; 96)
75 R_CURLY@[96; 97)
76 WHITESPACE@[97; 102)
77 BLOCK_EXPR@[102; 104)
78 L_CURLY@[102; 103)
79 R_CURLY@[103; 104)
80 WHITESPACE@[104; 105)
81 R_CURLY@[105; 106)
82 WHITESPACE@[106; 107)