diff options
author | pcpthm <[email protected]> | 2019-03-19 08:24:02 +0000 |
---|---|---|
committer | pcpthm <[email protected]> | 2019-03-19 08:24:02 +0000 |
commit | ffed132e52964f029a586a3efd4afc879ed39c59 (patch) | |
tree | d385c3239f92995bf56db209ab2464b50aa033d0 /crates/ra_parser | |
parent | 1cd18f9237b6ac48ca8461307f2a4eaf273ee394 (diff) |
Allow attributes on top level expression
A top level expression is either
- a expression statement or
- the last expression in a block
Diffstat (limited to 'crates/ra_parser')
-rw-r--r-- | crates/ra_parser/src/event.rs | 4 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 83 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/expressions/atom.rs | 4 | ||||
-rw-r--r-- | crates/ra_parser/src/parser.rs | 23 |
4 files changed, 79 insertions, 35 deletions
diff --git a/crates/ra_parser/src/event.rs b/crates/ra_parser/src/event.rs index 6361d5d86..c1773e8e0 100644 --- a/crates/ra_parser/src/event.rs +++ b/crates/ra_parser/src/event.rs | |||
@@ -105,7 +105,9 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) { | |||
105 | // append `A`'s forward_parent `B` | 105 | // append `A`'s forward_parent `B` |
106 | fp = match mem::replace(&mut events[idx], Event::tombstone()) { | 106 | fp = match mem::replace(&mut events[idx], Event::tombstone()) { |
107 | Event::Start { kind, forward_parent } => { | 107 | Event::Start { kind, forward_parent } => { |
108 | forward_parents.push(kind); | 108 | if kind != TOMBSTONE { |
109 | forward_parents.push(kind); | ||
110 | } | ||
109 | forward_parent | 111 | forward_parent |
110 | } | 112 | } |
111 | _ => unreachable!(), | 113 | _ => unreachable!(), |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 83812e938..e35c46a5e 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -8,10 +8,10 @@ const EXPR_FIRST: TokenSet = LHS_FIRST; | |||
8 | 8 | ||
9 | pub(super) fn expr(p: &mut Parser) -> BlockLike { | 9 | pub(super) fn expr(p: &mut Parser) -> BlockLike { |
10 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; | 10 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; |
11 | expr_bp(p, r, 1) | 11 | expr_bp(p, r, 1).1 |
12 | } | 12 | } |
13 | 13 | ||
14 | pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { | 14 | pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { |
15 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; | 15 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; |
16 | expr_bp(p, r, 1) | 16 | expr_bp(p, r, 1) |
17 | } | 17 | } |
@@ -55,7 +55,13 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { | |||
55 | // test block_items | 55 | // test block_items |
56 | // fn a() { fn b() {} } | 56 | // fn a() { fn b() {} } |
57 | let m = p.start(); | 57 | let m = p.start(); |
58 | let has_attrs = p.at(POUND); | 58 | // test attr_on_expr_stmt |
59 | // fn foo() { | ||
60 | // #[A] foo(); | ||
61 | // #[B] bar!{} | ||
62 | // #[C] #[D] {} | ||
63 | // #[D] return (); | ||
64 | // } | ||
59 | attributes::outer_attributes(p); | 65 | attributes::outer_attributes(p); |
60 | if p.at(LET_KW) { | 66 | if p.at(LET_KW) { |
61 | let_stmt(p, m); | 67 | let_stmt(p, m); |
@@ -67,35 +73,48 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { | |||
67 | Err(m) => m, | 73 | Err(m) => m, |
68 | }; | 74 | }; |
69 | 75 | ||
70 | if has_attrs { | 76 | let (cm, blocklike) = expr_stmt(p); |
71 | m.abandon(p); | 77 | let cm = match cm { |
72 | p.error("expected a let statement or an item after attributes in block"); | 78 | None => { |
73 | } else { | 79 | if p.at(R_CURLY) { |
74 | let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block; | 80 | m.abandon(p); |
75 | if p.at(R_CURLY) { | ||
76 | m.abandon(p); | ||
77 | } else { | ||
78 | // test no_semi_after_block | ||
79 | // fn foo() { | ||
80 | // if true {} | ||
81 | // loop {} | ||
82 | // match () {} | ||
83 | // while true {} | ||
84 | // for _ in () {} | ||
85 | // {} | ||
86 | // {} | ||
87 | // macro_rules! test { | ||
88 | // () => {} | ||
89 | // } | ||
90 | // test!{} | ||
91 | // } | ||
92 | if is_blocklike { | ||
93 | p.eat(SEMI); | ||
94 | } else { | 81 | } else { |
95 | p.expect(SEMI); | 82 | p.expect(SEMI); |
83 | m.complete(p, EXPR_STMT); | ||
96 | } | 84 | } |
97 | m.complete(p, EXPR_STMT); | 85 | continue; |
86 | } | ||
87 | Some(cm) => cm, | ||
88 | }; | ||
89 | |||
90 | if p.at(R_CURLY) { | ||
91 | // test attr_on_last_expr_in_block | ||
92 | // fn foo() { | ||
93 | // { #[A] bar!()? } | ||
94 | // #[B] &() | ||
95 | // } | ||
96 | m.contract_child(p, cm); | ||
97 | } else { | ||
98 | // test no_semi_after_block | ||
99 | // fn foo() { | ||
100 | // if true {} | ||
101 | // loop {} | ||
102 | // match () {} | ||
103 | // while true {} | ||
104 | // for _ in () {} | ||
105 | // {} | ||
106 | // {} | ||
107 | // macro_rules! test { | ||
108 | // () => {} | ||
109 | // } | ||
110 | // test!{} | ||
111 | // } | ||
112 | if blocklike.is_block() { | ||
113 | p.eat(SEMI); | ||
114 | } else { | ||
115 | p.expect(SEMI); | ||
98 | } | 116 | } |
117 | m.complete(p, EXPR_STMT); | ||
99 | } | 118 | } |
100 | } | 119 | } |
101 | 120 | ||
@@ -176,7 +195,7 @@ fn current_op(p: &Parser) -> (u8, Op) { | |||
176 | } | 195 | } |
177 | 196 | ||
178 | // Parses expression with binding power of at least bp. | 197 | // Parses expression with binding power of at least bp. |
179 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | 198 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) { |
180 | let mut lhs = match lhs(p, r) { | 199 | let mut lhs = match lhs(p, r) { |
181 | Some((lhs, blocklike)) => { | 200 | Some((lhs, blocklike)) => { |
182 | // test stmt_bin_expr_ambiguity | 201 | // test stmt_bin_expr_ambiguity |
@@ -185,11 +204,11 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | |||
185 | // {1} &2; | 204 | // {1} &2; |
186 | // } | 205 | // } |
187 | if r.prefer_stmt && blocklike.is_block() { | 206 | if r.prefer_stmt && blocklike.is_block() { |
188 | return BlockLike::Block; | 207 | return (Some(lhs), BlockLike::Block); |
189 | } | 208 | } |
190 | lhs | 209 | lhs |
191 | } | 210 | } |
192 | None => return BlockLike::NotBlock, | 211 | None => return (None, BlockLike::NotBlock), |
193 | }; | 212 | }; |
194 | 213 | ||
195 | loop { | 214 | loop { |
@@ -208,7 +227,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { | |||
208 | expr_bp(p, r, op_bp + 1); | 227 | expr_bp(p, r, op_bp + 1); |
209 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | 228 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); |
210 | } | 229 | } |
211 | BlockLike::NotBlock | 230 | (Some(lhs), BlockLike::NotBlock) |
212 | } | 231 | } |
213 | 232 | ||
214 | const LHS_FIRST: TokenSet = | 233 | const LHS_FIRST: TokenSet = |
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index d933288cd..a23977bfb 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs | |||
@@ -392,9 +392,9 @@ fn match_arm(p: &mut Parser) -> BlockLike { | |||
392 | match_guard(p); | 392 | match_guard(p); |
393 | } | 393 | } |
394 | p.expect(FAT_ARROW); | 394 | p.expect(FAT_ARROW); |
395 | let ret = expr_stmt(p); | 395 | let blocklike = expr_stmt(p).1; |
396 | m.complete(p, MATCH_ARM); | 396 | m.complete(p, MATCH_ARM); |
397 | ret | 397 | blocklike |
398 | } | 398 | } |
399 | 399 | ||
400 | // test match_guard | 400 | // test match_guard |
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs index a18458148..702669eb9 100644 --- a/crates/ra_parser/src/parser.rs +++ b/crates/ra_parser/src/parser.rs | |||
@@ -228,6 +228,29 @@ impl Marker { | |||
228 | } | 228 | } |
229 | } | 229 | } |
230 | } | 230 | } |
231 | |||
232 | /// Contract a node `cm` and complete as `cm`'s `kind`. | ||
233 | /// `cm` must be a child of `m` to work correctly. | ||
234 | /// ``` | ||
235 | /// m--A m--A | ||
236 | /// +--cm--B -> +--B | ||
237 | /// +--C C | ||
238 | /// | ||
239 | /// [m: TOMBSTONE, A, cm: Start(k), B, Finish, C] | ||
240 | /// [m: Start(k), A, cm: TOMBSTONE, B, Finish, C] | ||
241 | /// ``` | ||
242 | pub(crate) fn contract_child(mut self, p: &mut Parser, cm: CompletedMarker) -> CompletedMarker { | ||
243 | self.bomb.defuse(); | ||
244 | match p.events[self.pos as usize] { | ||
245 | Event::Start { kind: ref mut slot, .. } => *slot = cm.kind(), | ||
246 | _ => unreachable!(), | ||
247 | }; | ||
248 | match p.events[cm.0 as usize] { | ||
249 | Event::Start { kind: ref mut slot, .. } => *slot = TOMBSTONE, | ||
250 | _ => unreachable!(), | ||
251 | }; | ||
252 | CompletedMarker::new(self.pos, cm.kind()) | ||
253 | } | ||
231 | } | 254 | } |
232 | 255 | ||
233 | pub(crate) struct CompletedMarker(u32, SyntaxKind); | 256 | pub(crate) struct CompletedMarker(u32, SyntaxKind); |