diff options
Diffstat (limited to 'crates/ra_syntax/src/parsing/builder.rs')
-rw-r--r-- | crates/ra_syntax/src/parsing/builder.rs | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/crates/ra_syntax/src/parsing/builder.rs b/crates/ra_syntax/src/parsing/builder.rs index 0775b0900..cfe3139b8 100644 --- a/crates/ra_syntax/src/parsing/builder.rs +++ b/crates/ra_syntax/src/parsing/builder.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use std::mem; | ||
2 | |||
1 | use ra_parser::{TreeSink, ParseError}; | 3 | use ra_parser::{TreeSink, ParseError}; |
4 | use rowan::GreenNodeBuilder; | ||
2 | 5 | ||
3 | use crate::{ | 6 | use crate::{ |
4 | SmolStr, SyntaxError, SyntaxErrorKind, TextUnit, TextRange, | 7 | SmolStr, SyntaxError, SyntaxErrorKind, TextUnit, TextRange, |
@@ -7,19 +10,32 @@ use crate::{ | |||
7 | syntax_node::{GreenNode, RaTypes}, | 10 | syntax_node::{GreenNode, RaTypes}, |
8 | }; | 11 | }; |
9 | 12 | ||
10 | use rowan::GreenNodeBuilder; | 13 | /// Bridges the parser with our specific syntax tree representation. |
11 | 14 | /// | |
15 | /// `TreeBuilder` also handles attachment of trivia (whitespace) to nodes. | ||
12 | pub(crate) struct TreeBuilder<'a> { | 16 | pub(crate) struct TreeBuilder<'a> { |
13 | text: &'a str, | 17 | text: &'a str, |
14 | tokens: &'a [Token], | 18 | tokens: &'a [Token], |
15 | text_pos: TextUnit, | 19 | text_pos: TextUnit, |
16 | token_pos: usize, | 20 | token_pos: usize, |
21 | state: State, | ||
17 | errors: Vec<SyntaxError>, | 22 | errors: Vec<SyntaxError>, |
18 | inner: GreenNodeBuilder<RaTypes>, | 23 | inner: GreenNodeBuilder<RaTypes>, |
19 | } | 24 | } |
20 | 25 | ||
26 | enum State { | ||
27 | PendingStart, | ||
28 | Normal, | ||
29 | PendingFinish, | ||
30 | } | ||
31 | |||
21 | impl<'a> TreeSink for TreeBuilder<'a> { | 32 | impl<'a> TreeSink for TreeBuilder<'a> { |
22 | fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { | 33 | fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { |
34 | match mem::replace(&mut self.state, State::Normal) { | ||
35 | State::PendingStart => unreachable!(), | ||
36 | State::PendingFinish => self.inner.finish_internal(), | ||
37 | State::Normal => (), | ||
38 | } | ||
23 | self.eat_trivias(); | 39 | self.eat_trivias(); |
24 | let n_tokens = n_tokens as usize; | 40 | let n_tokens = n_tokens as usize; |
25 | let len = self.tokens[self.token_pos..self.token_pos + n_tokens] | 41 | let len = self.tokens[self.token_pos..self.token_pos + n_tokens] |
@@ -29,11 +45,18 @@ impl<'a> TreeSink for TreeBuilder<'a> { | |||
29 | self.do_leaf(kind, len, n_tokens); | 45 | self.do_leaf(kind, len, n_tokens); |
30 | } | 46 | } |
31 | 47 | ||
32 | fn start_branch(&mut self, kind: SyntaxKind, root: bool) { | 48 | fn start_branch(&mut self, kind: SyntaxKind) { |
33 | if root { | 49 | match mem::replace(&mut self.state, State::Normal) { |
34 | self.inner.start_internal(kind); | 50 | State::PendingStart => { |
35 | return; | 51 | self.inner.start_internal(kind); |
52 | // No need to attach trivias to previous node: there is no | ||
53 | // previous node. | ||
54 | return; | ||
55 | } | ||
56 | State::PendingFinish => self.inner.finish_internal(), | ||
57 | State::Normal => (), | ||
36 | } | 58 | } |
59 | |||
37 | let n_trivias = | 60 | let n_trivias = |
38 | self.tokens[self.token_pos..].iter().take_while(|it| it.kind.is_trivia()).count(); | 61 | self.tokens[self.token_pos..].iter().take_while(|it| it.kind.is_trivia()).count(); |
39 | let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias]; | 62 | let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias]; |
@@ -54,11 +77,12 @@ impl<'a> TreeSink for TreeBuilder<'a> { | |||
54 | self.eat_n_trivias(n_attached_trivias); | 77 | self.eat_n_trivias(n_attached_trivias); |
55 | } | 78 | } |
56 | 79 | ||
57 | fn finish_branch(&mut self, root: bool) { | 80 | fn finish_branch(&mut self) { |
58 | if root { | 81 | match mem::replace(&mut self.state, State::PendingFinish) { |
59 | self.eat_trivias() | 82 | State::PendingStart => unreachable!(), |
83 | State::PendingFinish => self.inner.finish_internal(), | ||
84 | State::Normal => (), | ||
60 | } | 85 | } |
61 | self.inner.finish_internal(); | ||
62 | } | 86 | } |
63 | 87 | ||
64 | fn error(&mut self, error: ParseError) { | 88 | fn error(&mut self, error: ParseError) { |
@@ -74,12 +98,21 @@ impl<'a> TreeBuilder<'a> { | |||
74 | tokens, | 98 | tokens, |
75 | text_pos: 0.into(), | 99 | text_pos: 0.into(), |
76 | token_pos: 0, | 100 | token_pos: 0, |
101 | state: State::PendingStart, | ||
77 | errors: Vec::new(), | 102 | errors: Vec::new(), |
78 | inner: GreenNodeBuilder::new(), | 103 | inner: GreenNodeBuilder::new(), |
79 | } | 104 | } |
80 | } | 105 | } |
81 | 106 | ||
82 | pub(super) fn finish(self) -> (GreenNode, Vec<SyntaxError>) { | 107 | pub(super) fn finish(mut self) -> (GreenNode, Vec<SyntaxError>) { |
108 | match mem::replace(&mut self.state, State::Normal) { | ||
109 | State::PendingFinish => { | ||
110 | self.eat_trivias(); | ||
111 | self.inner.finish_internal() | ||
112 | } | ||
113 | State::PendingStart | State::Normal => unreachable!(), | ||
114 | } | ||
115 | |||
83 | (self.inner.finish(), self.errors) | 116 | (self.inner.finish(), self.errors) |
84 | } | 117 | } |
85 | 118 | ||