diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-19 10:36:17 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-19 10:36:17 +0000 |
commit | 5b6ad0971c050981deb10c56ad2634293f104228 (patch) | |
tree | 7f76ce1da6ed9e245f5b4ef14257418c66f59577 /crates/ra_parser/src/parser.rs | |
parent | 91576afc7e64f11dde2bed14b578e4914d253a6a (diff) | |
parent | 4cf179c089aeed381cd67bcd265e76a27f11facd (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/src/parser.rs')
-rw-r--r-- | crates/ra_parser/src/parser.rs | 34 |
1 files changed, 27 insertions, 7 deletions
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 | ||
233 | pub(crate) struct CompletedMarker(u32, SyntaxKind); | 234 | pub(crate) struct CompletedMarker { |
235 | start_pos: u32, | ||
236 | finish_pos: u32, | ||
237 | kind: SyntaxKind, | ||
238 | } | ||
234 | 239 | ||
235 | impl CompletedMarker { | 240 | impl 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 | } |