aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grammar.ron1
-rw-r--r--src/grammar/expressions/atom.rs4
-rw-r--r--src/grammar/expressions/mod.rs47
-rw-r--r--src/grammar/patterns.rs23
-rw-r--r--src/syntax_kinds/generated.rs2
-rw-r--r--tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs7
-rw-r--r--tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt58
-rw-r--r--tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs4
-rw-r--r--tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt50
-rw-r--r--tests/data/parser/inline/0089_slice_pat.rs3
-rw-r--r--tests/data/parser/inline/0089_slice_pat.txt40
11 files changed, 224 insertions, 15 deletions
diff --git a/src/grammar.ron b/src/grammar.ron
index 960838c97..f1c3502bc 100644
--- a/src/grammar.ron
+++ b/src/grammar.ron
@@ -142,6 +142,7 @@ Grammar(
142 "STRUCT_PAT", 142 "STRUCT_PAT",
143 "TUPLE_STRUCT_PAT", 143 "TUPLE_STRUCT_PAT",
144 "TUPLE_PAT", 144 "TUPLE_PAT",
145 "SLICE_PAT",
145 146
146 // atoms 147 // atoms
147 "TUPLE_EXPR", 148 "TUPLE_EXPR",
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}
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// }
136fn 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 = ();
diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs
index cf286a0f1..0c6a1f8e7 100644
--- a/src/syntax_kinds/generated.rs
+++ b/src/syntax_kinds/generated.rs
@@ -134,6 +134,7 @@ pub enum SyntaxKind {
134 STRUCT_PAT, 134 STRUCT_PAT,
135 TUPLE_STRUCT_PAT, 135 TUPLE_STRUCT_PAT,
136 TUPLE_PAT, 136 TUPLE_PAT,
137 SLICE_PAT,
137 TUPLE_EXPR, 138 TUPLE_EXPR,
138 ARRAY_EXPR, 139 ARRAY_EXPR,
139 PAREN_EXPR, 140 PAREN_EXPR,
@@ -372,6 +373,7 @@ impl SyntaxKind {
372 STRUCT_PAT => &SyntaxInfo { name: "STRUCT_PAT" }, 373 STRUCT_PAT => &SyntaxInfo { name: "STRUCT_PAT" },
373 TUPLE_STRUCT_PAT => &SyntaxInfo { name: "TUPLE_STRUCT_PAT" }, 374 TUPLE_STRUCT_PAT => &SyntaxInfo { name: "TUPLE_STRUCT_PAT" },
374 TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" }, 375 TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" },
376 SLICE_PAT => &SyntaxInfo { name: "SLICE_PAT" },
375 TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" }, 377 TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" },
376 ARRAY_EXPR => &SyntaxInfo { name: "ARRAY_EXPR" }, 378 ARRAY_EXPR => &SyntaxInfo { name: "ARRAY_EXPR" },
377 PAREN_EXPR => &SyntaxInfo { name: "PAREN_EXPR" }, 379 PAREN_EXPR => &SyntaxInfo { name: "PAREN_EXPR" },
diff --git a/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs b/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs
new file mode 100644
index 000000000..2edd578f9
--- /dev/null
+++ b/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs
@@ -0,0 +1,7 @@
1fn foo() {
2 match () {
3 _ => {}
4 () => {}
5 [] => {}
6 }
7}
diff --git a/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt b/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt
new file mode 100644
index 000000000..47b4d4481
--- /dev/null
+++ b/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt
@@ -0,0 +1,58 @@
1FILE@[0; 84)
2 FN_ITEM@[0; 83)
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; 83)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 MATCH_EXPR@[15; 81)
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 BLOCK_EXPR@[39; 41)
30 L_CURLY@[39; 40)
31 R_CURLY@[40; 41)
32 WHITESPACE@[41; 50)
33 MATCH_ARM@[50; 58)
34 TUPLE_PAT@[50; 52)
35 L_PAREN@[50; 51)
36 R_PAREN@[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; 75)
45 SLICE_PAT@[67; 69)
46 L_BRACK@[67; 68)
47 R_BRACK@[68; 69)
48 WHITESPACE@[69; 70)
49 FAT_ARROW@[70; 72)
50 WHITESPACE@[72; 73)
51 BLOCK_EXPR@[73; 75)
52 L_CURLY@[73; 74)
53 R_CURLY@[74; 75)
54 WHITESPACE@[75; 80)
55 R_CURLY@[80; 81)
56 WHITESPACE@[81; 82)
57 R_CURLY@[82; 83)
58 WHITESPACE@[83; 84)
diff --git a/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs b/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs
new file mode 100644
index 000000000..37b843742
--- /dev/null
+++ b/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 let _ = {1} & 2;
3 {1} &2;
4}
diff --git a/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt b/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt
new file mode 100644
index 000000000..df0aa44b3
--- /dev/null
+++ b/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt
@@ -0,0 +1,50 @@
1FILE@[0; 46)
2 FN_ITEM@[0; 45)
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; 45)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 31)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PLACEHOLDER_PAT@[19; 20)
18 UNDERSCORE@[19; 20)
19 WHITESPACE@[20; 21)
20 EQ@[21; 22)
21 WHITESPACE@[22; 23)
22 BIN_EXPR@[23; 30)
23 BLOCK_EXPR@[23; 26)
24 L_CURLY@[23; 24)
25 LITERAL@[24; 25)
26 INT_NUMBER@[24; 25) "1"
27 R_CURLY@[25; 26)
28 WHITESPACE@[26; 27)
29 AMP@[27; 28)
30 WHITESPACE@[28; 29)
31 LITERAL@[29; 30)
32 INT_NUMBER@[29; 30) "2"
33 SEMI@[30; 31)
34 WHITESPACE@[31; 36)
35 EXPR_STMT@[36; 39)
36 BLOCK_EXPR@[36; 39)
37 L_CURLY@[36; 37)
38 LITERAL@[37; 38)
39 INT_NUMBER@[37; 38) "1"
40 R_CURLY@[38; 39)
41 WHITESPACE@[39; 40)
42 EXPR_STMT@[40; 43)
43 REF_EXPR@[40; 42)
44 AMP@[40; 41)
45 LITERAL@[41; 42)
46 INT_NUMBER@[41; 42) "2"
47 SEMI@[42; 43)
48 WHITESPACE@[43; 44)
49 R_CURLY@[44; 45)
50 WHITESPACE@[45; 46)
diff --git a/tests/data/parser/inline/0089_slice_pat.rs b/tests/data/parser/inline/0089_slice_pat.rs
new file mode 100644
index 000000000..7955973b9
--- /dev/null
+++ b/tests/data/parser/inline/0089_slice_pat.rs
@@ -0,0 +1,3 @@
1fn main() {
2 let [a, b, ..] = [];
3}
diff --git a/tests/data/parser/inline/0089_slice_pat.txt b/tests/data/parser/inline/0089_slice_pat.txt
new file mode 100644
index 000000000..1e7f20119
--- /dev/null
+++ b/tests/data/parser/inline/0089_slice_pat.txt
@@ -0,0 +1,40 @@
1FILE@[0; 39)
2 FN_ITEM@[0; 38)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 38)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 LET_STMT@[16; 36)
15 LET_KW@[16; 19)
16 WHITESPACE@[19; 20)
17 SLICE_PAT@[20; 30)
18 L_BRACK@[20; 21)
19 BIND_PAT@[21; 22)
20 NAME@[21; 22)
21 IDENT@[21; 22) "a"
22 COMMA@[22; 23)
23 WHITESPACE@[23; 24)
24 BIND_PAT@[24; 25)
25 NAME@[24; 25)
26 IDENT@[24; 25) "b"
27 COMMA@[25; 26)
28 WHITESPACE@[26; 27)
29 DOTDOT@[27; 29)
30 R_BRACK@[29; 30)
31 WHITESPACE@[30; 31)
32 EQ@[31; 32)
33 WHITESPACE@[32; 33)
34 ARRAY_EXPR@[33; 35)
35 L_BRACK@[33; 34)
36 R_BRACK@[34; 35)
37 SEMI@[35; 36)
38 WHITESPACE@[36; 37)
39 R_CURLY@[37; 38)
40 WHITESPACE@[38; 39)