aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-03-19 10:36:17 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-03-19 10:36:17 +0000
commit5b6ad0971c050981deb10c56ad2634293f104228 (patch)
tree7f76ce1da6ed9e245f5b4ef14257418c66f59577 /crates/ra_parser
parent91576afc7e64f11dde2bed14b578e4914d253a6a (diff)
parent4cf179c089aeed381cd67bcd265e76a27f11facd (diff)
Merge #996
996: Allow attributes on top level expressions r=matklad a=pcpthm This PR modifies parser to allow outer attributes on top level expression. Here, top level expression means either - Expression statement e.g. `foo();` - Last expression in a block without semicolon `bar()` in `{ foo(); bar() }`. Except for binary operation expressions and `if` expressions, which are errors (feature gated) in rustc. Attributes on inner expressions like `foo(#[a] 1)` are not implemented. I first tried to implement this by passing `Maker` to expression parsers. However, this implementation couldn't parse `#[attr] foo()` correctly as `CallExpr(Attr(..), PathExpr(..), ArgList(..))` and instead parsed incorrectly as `CallExpr(PathExpr(Attr(..), ..), ArgList(..))` due to the way left recursion is handled. In the end, I introduce `undo_completion` method. Which is not the suggested approach, but it seems not very bad. Fix #759. Co-authored-by: pcpthm <[email protected]>
Diffstat (limited to 'crates/ra_parser')
-rw-r--r--crates/ra_parser/src/event.rs4
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs94
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs4
-rw-r--r--crates/ra_parser/src/parser.rs34
4 files changed, 94 insertions, 42 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..73e1acd5a 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
9pub(super) fn expr(p: &mut Parser) -> BlockLike { 9pub(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
14pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { 14pub(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}
@@ -38,6 +38,13 @@ pub(crate) fn block(p: &mut Parser) {
38 m.complete(p, BLOCK); 38 m.complete(p, BLOCK);
39} 39}
40 40
41fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
42 match kind {
43 BIN_EXPR | RANGE_EXPR | IF_EXPR => false,
44 _ => true,
45 }
46}
47
41pub(crate) fn expr_block_contents(p: &mut Parser) { 48pub(crate) fn expr_block_contents(p: &mut Parser) {
42 // This is checked by a validator 49 // This is checked by a validator
43 attributes::inner_attributes(p); 50 attributes::inner_attributes(p);
@@ -55,6 +62,13 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
55 // test block_items 62 // test block_items
56 // fn a() { fn b() {} } 63 // fn a() { fn b() {} }
57 let m = p.start(); 64 let m = p.start();
65 // test attr_on_expr_stmt
66 // fn foo() {
67 // #[A] foo();
68 // #[B] bar!{}
69 // #[C] #[D] {}
70 // #[D] return ();
71 // }
58 let has_attrs = p.at(POUND); 72 let has_attrs = p.at(POUND);
59 attributes::outer_attributes(p); 73 attributes::outer_attributes(p);
60 if p.at(LET_KW) { 74 if p.at(LET_KW) {
@@ -67,35 +81,51 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
67 Err(m) => m, 81 Err(m) => m,
68 }; 82 };
69 83
70 if has_attrs { 84 let (cm, blocklike) = expr_stmt(p);
71 m.abandon(p); 85 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
72 p.error("expected a let statement or an item after attributes in block"); 86
73 } else { 87 if has_attrs && !is_expr_stmt_attr_allowed(kind) {
74 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block; 88 // test_err attr_on_expr_not_allowed
75 if p.at(R_CURLY) { 89 // fn foo() {
90 // #[A] 1 + 2;
91 // #[B] if true {};
92 // }
93 p.error(format!("attributes are not allowed on {:?}", kind));
94 }
95
96 if p.at(R_CURLY) {
97 // test attr_on_last_expr_in_block
98 // fn foo() {
99 // { #[A] bar!()? }
100 // #[B] &()
101 // }
102 if let Some(cm) = cm {
103 cm.undo_completion(p).abandon(p);
104 m.complete(p, kind);
105 } else {
76 m.abandon(p); 106 m.abandon(p);
107 }
108 } else {
109 // test no_semi_after_block
110 // fn foo() {
111 // if true {}
112 // loop {}
113 // match () {}
114 // while true {}
115 // for _ in () {}
116 // {}
117 // {}
118 // macro_rules! test {
119 // () => {}
120 // }
121 // test!{}
122 // }
123 if blocklike.is_block() {
124 p.eat(SEMI);
77 } else { 125 } else {
78 // test no_semi_after_block 126 p.expect(SEMI);
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 {
95 p.expect(SEMI);
96 }
97 m.complete(p, EXPR_STMT);
98 } 127 }
128 m.complete(p, EXPR_STMT);
99 } 129 }
100 } 130 }
101 131
@@ -176,7 +206,7 @@ fn current_op(p: &Parser) -> (u8, Op) {
176} 206}
177 207
178// Parses expression with binding power of at least bp. 208// Parses expression with binding power of at least bp.
179fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { 209fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
180 let mut lhs = match lhs(p, r) { 210 let mut lhs = match lhs(p, r) {
181 Some((lhs, blocklike)) => { 211 Some((lhs, blocklike)) => {
182 // test stmt_bin_expr_ambiguity 212 // test stmt_bin_expr_ambiguity
@@ -185,11 +215,11 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
185 // {1} &2; 215 // {1} &2;
186 // } 216 // }
187 if r.prefer_stmt && blocklike.is_block() { 217 if r.prefer_stmt && blocklike.is_block() {
188 return BlockLike::Block; 218 return (Some(lhs), BlockLike::Block);
189 } 219 }
190 lhs 220 lhs
191 } 221 }
192 None => return BlockLike::NotBlock, 222 None => return (None, BlockLike::NotBlock),
193 }; 223 };
194 224
195 loop { 225 loop {
@@ -208,7 +238,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
208 expr_bp(p, r, op_bp + 1); 238 expr_bp(p, r, op_bp + 1);
209 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); 239 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
210 } 240 }
211 BlockLike::NotBlock 241 (Some(lhs), BlockLike::NotBlock)
212} 242}
213 243
214const LHS_FIRST: TokenSet = 244const 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..3c326452b 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -212,8 +212,9 @@ impl Marker {
212 } 212 }
213 _ => unreachable!(), 213 _ => unreachable!(),
214 } 214 }
215 let finish_pos = p.events.len() as u32;
215 p.push_event(Event::Finish); 216 p.push_event(Event::Finish);
216 CompletedMarker::new(self.pos, kind) 217 CompletedMarker::new(self.pos, finish_pos, kind)
217 } 218 }
218 219
219 /// Abandons the syntax tree node. All its children 220 /// Abandons the syntax tree node. All its children
@@ -230,11 +231,15 @@ impl Marker {
230 } 231 }
231} 232}
232 233
233pub(crate) struct CompletedMarker(u32, SyntaxKind); 234pub(crate) struct CompletedMarker {
235 start_pos: u32,
236 finish_pos: u32,
237 kind: SyntaxKind,
238}
234 239
235impl CompletedMarker { 240impl CompletedMarker {
236 fn new(pos: u32, kind: SyntaxKind) -> Self { 241 fn new(start_pos: u32, finish_pos: u32, kind: SyntaxKind) -> Self {
237 CompletedMarker(pos, kind) 242 CompletedMarker { start_pos, finish_pos, kind }
238 } 243 }
239 244
240 /// This method allows to create a new node which starts 245 /// This method allows to create a new node which starts
@@ -251,17 +256,32 @@ impl CompletedMarker {
251 /// distance to `NEWSTART` into forward_parent(=2 in this case); 256 /// distance to `NEWSTART` into forward_parent(=2 in this case);
252 pub(crate) fn precede(self, p: &mut Parser) -> Marker { 257 pub(crate) fn precede(self, p: &mut Parser) -> Marker {
253 let new_pos = p.start(); 258 let new_pos = p.start();
254 let idx = self.0 as usize; 259 let idx = self.start_pos as usize;
255 match p.events[idx] { 260 match p.events[idx] {
256 Event::Start { ref mut forward_parent, .. } => { 261 Event::Start { ref mut forward_parent, .. } => {
257 *forward_parent = Some(new_pos.pos - self.0); 262 *forward_parent = Some(new_pos.pos - self.start_pos);
258 } 263 }
259 _ => unreachable!(), 264 _ => unreachable!(),
260 } 265 }
261 new_pos 266 new_pos
262 } 267 }
263 268
269 /// Undo this completion and turns into a `Marker`
270 pub(crate) fn undo_completion(self, p: &mut Parser) -> Marker {
271 let start_idx = self.start_pos as usize;
272 let finish_idx = self.finish_pos as usize;
273 match p.events[start_idx] {
274 Event::Start { ref mut kind, forward_parent: None } => *kind = TOMBSTONE,
275 _ => unreachable!(),
276 }
277 match p.events[finish_idx] {
278 ref mut slot @ Event::Finish => *slot = Event::tombstone(),
279 _ => unreachable!(),
280 }
281 Marker::new(self.start_pos)
282 }
283
264 pub(crate) fn kind(&self) -> SyntaxKind { 284 pub(crate) fn kind(&self) -> SyntaxKind {
265 self.1 285 self.kind
266 } 286 }
267} 287}