diff options
Diffstat (limited to 'crates/ra_syntax/src/parsing')
-rw-r--r-- | crates/ra_syntax/src/parsing/builder.rs | 55 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/input.rs | 40 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/reparsing.rs | 11 |
3 files changed, 73 insertions, 33 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 | ||
diff --git a/crates/ra_syntax/src/parsing/input.rs b/crates/ra_syntax/src/parsing/input.rs index 58be795bc..31c6a3b9b 100644 --- a/crates/ra_syntax/src/parsing/input.rs +++ b/crates/ra_syntax/src/parsing/input.rs | |||
@@ -5,6 +5,26 @@ use crate::{ | |||
5 | parsing::lexer::Token, | 5 | parsing::lexer::Token, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | pub(crate) struct ParserInput<'t> { | ||
9 | text: &'t str, | ||
10 | /// start position of each token(expect whitespace and comment) | ||
11 | /// ```non-rust | ||
12 | /// struct Foo; | ||
13 | /// ^------^--- | ||
14 | /// | | ^- | ||
15 | /// 0 7 10 | ||
16 | /// ``` | ||
17 | /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]` | ||
18 | start_offsets: Vec<TextUnit>, | ||
19 | /// non-whitespace/comment tokens | ||
20 | /// ```non-rust | ||
21 | /// struct Foo {} | ||
22 | /// ^^^^^^ ^^^ ^^ | ||
23 | /// ``` | ||
24 | /// tokens: `[struct, Foo, {, }]` | ||
25 | tokens: Vec<Token>, | ||
26 | } | ||
27 | |||
8 | impl<'t> TokenSource for ParserInput<'t> { | 28 | impl<'t> TokenSource for ParserInput<'t> { |
9 | fn token_kind(&self, pos: usize) -> SyntaxKind { | 29 | fn token_kind(&self, pos: usize) -> SyntaxKind { |
10 | if !(pos < self.tokens.len()) { | 30 | if !(pos < self.tokens.len()) { |
@@ -28,26 +48,6 @@ impl<'t> TokenSource for ParserInput<'t> { | |||
28 | } | 48 | } |
29 | } | 49 | } |
30 | 50 | ||
31 | pub(crate) struct ParserInput<'t> { | ||
32 | text: &'t str, | ||
33 | /// start position of each token(expect whitespace and comment) | ||
34 | /// ```non-rust | ||
35 | /// struct Foo; | ||
36 | /// ^------^--- | ||
37 | /// | | ^- | ||
38 | /// 0 7 10 | ||
39 | /// ``` | ||
40 | /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]` | ||
41 | start_offsets: Vec<TextUnit>, | ||
42 | /// non-whitespace/comment tokens | ||
43 | /// ```non-rust | ||
44 | /// struct Foo {} | ||
45 | /// ^^^^^^ ^^^ ^^ | ||
46 | /// ``` | ||
47 | /// tokens: `[struct, Foo, {, }]` | ||
48 | tokens: Vec<Token>, | ||
49 | } | ||
50 | |||
51 | impl<'t> ParserInput<'t> { | 51 | impl<'t> ParserInput<'t> { |
52 | /// Generate input from tokens(expect comment and whitespace). | 52 | /// Generate input from tokens(expect comment and whitespace). |
53 | pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> ParserInput<'t> { | 53 | pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> ParserInput<'t> { |
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index ffcb512ad..6957c26c0 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs | |||
@@ -1,11 +1,18 @@ | |||
1 | //! Implementation of incremental re-parsing. | ||
2 | //! | ||
3 | //! We use two simple strategies for this: | ||
4 | //! - if the edit modifies only a single token (like changing an identifier's | ||
5 | //! letter), we replace only this token. | ||
6 | //! - otherwise, we search for the nearest `{}` block which contains the edit | ||
7 | //! and try to parse only this block. | ||
8 | |||
1 | use ra_text_edit::AtomTextEdit; | 9 | use ra_text_edit::AtomTextEdit; |
2 | use ra_parser::Reparser; | 10 | use ra_parser::Reparser; |
3 | 11 | ||
4 | use crate::{ | 12 | use crate::{ |
5 | SyntaxKind::*, TextRange, TextUnit, | 13 | SyntaxKind::*, TextRange, TextUnit, SyntaxError, |
6 | algo, | 14 | algo, |
7 | syntax_node::{GreenNode, SyntaxNode}, | 15 | syntax_node::{GreenNode, SyntaxNode}, |
8 | syntax_error::SyntaxError, | ||
9 | parsing::{ | 16 | parsing::{ |
10 | input::ParserInput, | 17 | input::ParserInput, |
11 | builder::TreeBuilder, | 18 | builder::TreeBuilder, |