aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 10:15:43 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 10:15:43 +0000
commitf6f160391db945a0dcc2f73b38926d6919f7c566 (patch)
tree060450b70c09357615f261d8acd032a647615dd7
parentc5e74cebdcbade069c0e1e81e298ab7d729e4cd5 (diff)
parent81bca78349afb9e15994f46401da0cfabfba04a1 (diff)
Merge #885
885: Parse token trees directy r=matklad a=matklad This takes advantage of the recent macro refactoring to directly parse token stream into a syntax tree. Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_mbe/Cargo.toml1
-rw-r--r--crates/ra_mbe/src/lib.rs63
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs147
-rw-r--r--crates/ra_syntax/src/lib.rs2
-rw-r--r--crates/ra_syntax/src/parsing.rs12
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs8
-rw-r--r--crates/ra_syntax/src/parsing/text_token_source.rs (renamed from crates/ra_syntax/src/parsing/input.rs)10
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs (renamed from crates/ra_syntax/src/parsing/builder.rs)40
-rw-r--r--crates/ra_syntax/src/syntax_node.rs51
10 files changed, 288 insertions, 47 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5912659d4..e697de588 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1066,6 +1066,7 @@ dependencies = [
1066name = "ra_mbe" 1066name = "ra_mbe"
1067version = "0.1.0" 1067version = "0.1.0"
1068dependencies = [ 1068dependencies = [
1069 "ra_parser 0.1.0",
1069 "ra_syntax 0.1.0", 1070 "ra_syntax 0.1.0",
1070 "ra_tt 0.1.0", 1071 "ra_tt 0.1.0",
1071 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1072 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index e7b8660e7..6e785f570 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -6,6 +6,7 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8ra_syntax = { path = "../ra_syntax" } 8ra_syntax = { path = "../ra_syntax" }
9ra_parser = { path = "../ra_parser" }
9tt = { path = "../ra_tt", package = "ra_tt" } 10tt = { path = "../ra_tt", package = "ra_tt" }
10 11
11rustc-hash = "1.0.0" 12rustc-hash = "1.0.0"
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index cdca3cafb..907402f5f 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -24,7 +24,7 @@ use ra_syntax::SmolStr;
24 24
25pub use tt::{Delimiter, Punct}; 25pub use tt::{Delimiter, Punct};
26 26
27pub use crate::syntax_bridge::ast_to_token_tree; 27pub use crate::syntax_bridge::{ast_to_token_tree, token_tree_to_ast_item_list};
28 28
29/// This struct contains AST for a single `macro_rules` definition. What might 29/// This struct contains AST for a single `macro_rules` definition. What might
30/// be very confusing is that AST has almost exactly the same shape as 30/// be very confusing is that AST has almost exactly the same shape as
@@ -164,14 +164,18 @@ impl_froms!(TokenTree: Leaf, Subtree);
164 crate::MacroRules::parse(&definition_tt).unwrap() 164 crate::MacroRules::parse(&definition_tt).unwrap()
165 } 165 }
166 166
167 fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) { 167 fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
168 let source_file = ast::SourceFile::parse(invocation); 168 let source_file = ast::SourceFile::parse(invocation);
169 let macro_invocation = 169 let macro_invocation =
170 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 170 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
171 171
172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); 172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
173 173
174 let expanded = rules.expand(&invocation_tt).unwrap(); 174 rules.expand(&invocation_tt).unwrap()
175 }
176
177 fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
178 let expanded = expand(rules, invocation);
175 assert_eq!(expanded.to_string(), expansion); 179 assert_eq!(expanded.to_string(), expansion);
176 } 180 }
177 181
@@ -268,4 +272,57 @@ impl_froms!(TokenTree: Leaf, Subtree);
268 assert_expansion(&rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;"); 272 assert_expansion(&rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
269 } 273 }
270 274
275 #[test]
276 fn expand_to_item_list() {
277 let rules = create_rules(
278 "
279 macro_rules! structs {
280 ($($i:ident),*) => {
281 $(struct $i { field: u32 } )*
282 }
283 }
284 ",
285 );
286 let expansion = expand(&rules, "structs!(Foo, Bar)");
287 let tree = token_tree_to_ast_item_list(&expansion);
288 assert_eq!(
289 tree.syntax().debug_dump().trim(),
290 r#"
291SOURCE_FILE@[0; 40)
292 STRUCT_DEF@[0; 20)
293 STRUCT_KW@[0; 6)
294 NAME@[6; 9)
295 IDENT@[6; 9) "Foo"
296 NAMED_FIELD_DEF_LIST@[9; 20)
297 L_CURLY@[9; 10)
298 NAMED_FIELD_DEF@[10; 19)
299 NAME@[10; 15)
300 IDENT@[10; 15) "field"
301 COLON@[15; 16)
302 PATH_TYPE@[16; 19)
303 PATH@[16; 19)
304 PATH_SEGMENT@[16; 19)
305 NAME_REF@[16; 19)
306 IDENT@[16; 19) "u32"
307 R_CURLY@[19; 20)
308 STRUCT_DEF@[20; 40)
309 STRUCT_KW@[20; 26)
310 NAME@[26; 29)
311 IDENT@[26; 29) "Bar"
312 NAMED_FIELD_DEF_LIST@[29; 40)
313 L_CURLY@[29; 30)
314 NAMED_FIELD_DEF@[30; 39)
315 NAME@[30; 35)
316 IDENT@[30; 35) "field"
317 COLON@[35; 36)
318 PATH_TYPE@[36; 39)
319 PATH@[36; 39)
320 PATH_SEGMENT@[36; 39)
321 NAME_REF@[36; 39)
322 IDENT@[36; 39) "u32"
323 R_CURLY@[39; 40)"#
324 .trim()
325 );
326 }
327
271} 328}
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 848c785f8..c1472bbe5 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -1,5 +1,6 @@
1use ra_parser::{TokenSource, TreeSink, ParseError};
1use ra_syntax::{ 2use ra_syntax::{
2 AstNode, SyntaxNode, TextRange, 3 AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, SyntaxTreeBuilder, TreeArc,
3 ast, SyntaxKind::*, TextUnit 4 ast, SyntaxKind::*, TextUnit
4}; 5};
5 6
@@ -19,6 +20,15 @@ pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)
19 Some((tt, token_map)) 20 Some((tt, token_map))
20} 21}
21 22
23/// Parses the token tree (result of macro expansion) as a sequence of items
24pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> TreeArc<ast::SourceFile> {
25 let token_source = TtTokenSource::new(tt);
26 let mut tree_sink = TtTreeSink::new(&token_source.tokens);
27 ra_parser::parse(&token_source, &mut tree_sink);
28 let syntax = tree_sink.inner.finish();
29 ast::SourceFile::cast(&syntax).unwrap().to_owned()
30}
31
22impl TokenMap { 32impl TokenMap {
23 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { 33 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> {
24 let idx = tt.0 as usize; 34 let idx = tt.0 as usize;
@@ -84,3 +94,138 @@ fn convert_tt(
84 let res = tt::Subtree { delimiter, token_trees }; 94 let res = tt::Subtree { delimiter, token_trees };
85 Some(res) 95 Some(res)
86} 96}
97
98struct TtTokenSource {
99 tokens: Vec<TtToken>,
100}
101
102struct TtToken {
103 kind: SyntaxKind,
104 is_joint_to_next: bool,
105 text: SmolStr,
106}
107
108impl TtTokenSource {
109 fn new(tt: &tt::Subtree) -> TtTokenSource {
110 let mut res = TtTokenSource { tokens: Vec::new() };
111 res.convert_subtree(tt);
112 res
113 }
114 fn convert_subtree(&mut self, sub: &tt::Subtree) {
115 self.push_delim(sub.delimiter, false);
116 sub.token_trees.iter().for_each(|tt| self.convert_tt(tt));
117 self.push_delim(sub.delimiter, true)
118 }
119 fn convert_tt(&mut self, tt: &tt::TokenTree) {
120 match tt {
121 tt::TokenTree::Leaf(leaf) => self.convert_leaf(leaf),
122 tt::TokenTree::Subtree(sub) => self.convert_subtree(sub),
123 }
124 }
125 fn convert_leaf(&mut self, leaf: &tt::Leaf) {
126 let tok = match leaf {
127 tt::Leaf::Literal(l) => TtToken {
128 kind: SyntaxKind::INT_NUMBER, // FIXME
129 is_joint_to_next: false,
130 text: l.text.clone(),
131 },
132 tt::Leaf::Punct(p) => {
133 let kind = match p.char {
134 // lexer may produce combpund tokens for these ones
135 '.' => DOT,
136 ':' => COLON,
137 '=' => EQ,
138 '!' => EXCL,
139 '-' => MINUS,
140 c => SyntaxKind::from_char(c).unwrap(),
141 };
142 let text = {
143 let mut buf = [0u8; 4];
144 let s: &str = p.char.encode_utf8(&mut buf);
145 SmolStr::new(s)
146 };
147 TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text }
148 }
149 tt::Leaf::Ident(ident) => {
150 let kind = SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT);
151 TtToken { kind, is_joint_to_next: false, text: ident.text.clone() }
152 }
153 };
154 self.tokens.push(tok)
155 }
156 fn push_delim(&mut self, d: tt::Delimiter, closing: bool) {
157 let (kinds, texts) = match d {
158 tt::Delimiter::Parenthesis => ([L_PAREN, R_PAREN], "()"),
159 tt::Delimiter::Brace => ([L_CURLY, R_CURLY], "{}"),
160 tt::Delimiter::Bracket => ([L_BRACK, R_BRACK], "[]"),
161 tt::Delimiter::None => return,
162 };
163 let idx = closing as usize;
164 let kind = kinds[idx];
165 let text = &texts[idx..texts.len() - (1 - idx)];
166 let tok = TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text) };
167 self.tokens.push(tok)
168 }
169}
170
171impl TokenSource for TtTokenSource {
172 fn token_kind(&self, pos: usize) -> SyntaxKind {
173 if let Some(tok) = self.tokens.get(pos) {
174 tok.kind
175 } else {
176 SyntaxKind::EOF
177 }
178 }
179 fn is_token_joint_to_next(&self, pos: usize) -> bool {
180 self.tokens[pos].is_joint_to_next
181 }
182 fn is_keyword(&self, pos: usize, kw: &str) -> bool {
183 self.tokens[pos].text == *kw
184 }
185}
186
187#[derive(Default)]
188struct TtTreeSink<'a> {
189 buf: String,
190 tokens: &'a [TtToken],
191 text_pos: TextUnit,
192 token_pos: usize,
193 inner: SyntaxTreeBuilder,
194}
195
196impl<'a> TtTreeSink<'a> {
197 fn new(tokens: &'a [TtToken]) -> TtTreeSink {
198 TtTreeSink {
199 buf: String::new(),
200 tokens,
201 text_pos: 0.into(),
202 token_pos: 0,
203 inner: SyntaxTreeBuilder::default(),
204 }
205 }
206}
207
208impl<'a> TreeSink for TtTreeSink<'a> {
209 fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) {
210 for _ in 0..n_tokens {
211 self.buf += self.tokens[self.token_pos].text.as_str();
212 self.token_pos += 1;
213 }
214 self.text_pos += TextUnit::of_str(&self.buf);
215 let text = SmolStr::new(self.buf.as_str());
216 self.buf.clear();
217 self.inner.leaf(kind, text)
218 }
219
220 fn start_branch(&mut self, kind: SyntaxKind) {
221 self.inner.start_branch(kind);
222 }
223
224 fn finish_branch(&mut self) {
225 self.inner.finish_branch();
226 }
227
228 fn error(&mut self, error: ParseError) {
229 self.inner.error(error, self.text_pos)
230 }
231}
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index e7d402446..7334d53ef 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -36,7 +36,7 @@ pub use crate::{
36 ast::AstNode, 36 ast::AstNode,
37 syntax_error::{SyntaxError, SyntaxErrorKind, Location}, 37 syntax_error::{SyntaxError, SyntaxErrorKind, Location},
38 syntax_text::SyntaxText, 38 syntax_text::SyntaxText,
39 syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc}, 39 syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder},
40 ptr::{SyntaxNodePtr, AstPtr}, 40 ptr::{SyntaxNodePtr, AstPtr},
41 parsing::{tokenize, Token}, 41 parsing::{tokenize, Token},
42}; 42};
diff --git a/crates/ra_syntax/src/parsing.rs b/crates/ra_syntax/src/parsing.rs
index cf573801c..ad5668a65 100644
--- a/crates/ra_syntax/src/parsing.rs
+++ b/crates/ra_syntax/src/parsing.rs
@@ -2,17 +2,13 @@
2//! incremental reparsing. 2//! incremental reparsing.
3 3
4mod lexer; 4mod lexer;
5mod input; 5mod text_token_source;
6mod builder; 6mod text_tree_sink;
7mod reparsing; 7mod reparsing;
8 8
9use crate::{ 9use crate::{
10 SyntaxError, 10 SyntaxError,
11 syntax_node::GreenNode, 11 syntax_node::GreenNode,
12 parsing::{
13 builder::TreeBuilder,
14 input::ParserInput,
15 },
16}; 12};
17 13
18pub use self::lexer::{tokenize, Token}; 14pub use self::lexer::{tokenize, Token};
@@ -21,8 +17,8 @@ pub(crate) use self::reparsing::incremental_reparse;
21 17
22pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) { 18pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) {
23 let tokens = tokenize(&text); 19 let tokens = tokenize(&text);
24 let token_source = ParserInput::new(text, &tokens); 20 let token_source = text_token_source::TextTokenSource::new(text, &tokens);
25 let mut tree_sink = TreeBuilder::new(text, &tokens); 21 let mut tree_sink = text_tree_sink::TextTreeSink::new(text, &tokens);
26 ra_parser::parse(&token_source, &mut tree_sink); 22 ra_parser::parse(&token_source, &mut tree_sink);
27 tree_sink.finish() 23 tree_sink.finish()
28} 24}
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index 19d8adcfb..ba77a3b6c 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -14,8 +14,8 @@ use crate::{
14 algo, 14 algo,
15 syntax_node::{GreenNode, SyntaxNode}, 15 syntax_node::{GreenNode, SyntaxNode},
16 parsing::{ 16 parsing::{
17 input::ParserInput, 17 text_token_source::TextTokenSource,
18 builder::TreeBuilder, 18 text_tree_sink::TextTreeSink,
19 lexer::{tokenize, Token}, 19 lexer::{tokenize, Token},
20 } 20 }
21}; 21};
@@ -68,8 +68,8 @@ fn reparse_block<'node>(
68 if !is_balanced(&tokens) { 68 if !is_balanced(&tokens) {
69 return None; 69 return None;
70 } 70 }
71 let token_source = ParserInput::new(&text, &tokens); 71 let token_source = TextTokenSource::new(&text, &tokens);
72 let mut tree_sink = TreeBuilder::new(&text, &tokens); 72 let mut tree_sink = TextTreeSink::new(&text, &tokens);
73 reparser.parse(&token_source, &mut tree_sink); 73 reparser.parse(&token_source, &mut tree_sink);
74 let (green, new_errors) = tree_sink.finish(); 74 let (green, new_errors) = tree_sink.finish();
75 Some((node, green, new_errors)) 75 Some((node, green, new_errors))
diff --git a/crates/ra_syntax/src/parsing/input.rs b/crates/ra_syntax/src/parsing/text_token_source.rs
index 31c6a3b9b..a6277f66f 100644
--- a/crates/ra_syntax/src/parsing/input.rs
+++ b/crates/ra_syntax/src/parsing/text_token_source.rs
@@ -5,7 +5,7 @@ use crate::{
5 parsing::lexer::Token, 5 parsing::lexer::Token,
6}; 6};
7 7
8pub(crate) struct ParserInput<'t> { 8pub(crate) struct TextTokenSource<'t> {
9 text: &'t str, 9 text: &'t str,
10 /// start position of each token(expect whitespace and comment) 10 /// start position of each token(expect whitespace and comment)
11 /// ```non-rust 11 /// ```non-rust
@@ -25,7 +25,7 @@ pub(crate) struct ParserInput<'t> {
25 tokens: Vec<Token>, 25 tokens: Vec<Token>,
26} 26}
27 27
28impl<'t> TokenSource for ParserInput<'t> { 28impl<'t> TokenSource for TextTokenSource<'t> {
29 fn token_kind(&self, pos: usize) -> SyntaxKind { 29 fn token_kind(&self, pos: usize) -> SyntaxKind {
30 if !(pos < self.tokens.len()) { 30 if !(pos < self.tokens.len()) {
31 return EOF; 31 return EOF;
@@ -48,9 +48,9 @@ impl<'t> TokenSource for ParserInput<'t> {
48 } 48 }
49} 49}
50 50
51impl<'t> ParserInput<'t> { 51impl<'t> TextTokenSource<'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]) -> TextTokenSource<'t> {
54 let mut tokens = Vec::new(); 54 let mut tokens = Vec::new();
55 let mut start_offsets = Vec::new(); 55 let mut start_offsets = Vec::new();
56 let mut len = 0.into(); 56 let mut len = 0.into();
@@ -62,6 +62,6 @@ impl<'t> ParserInput<'t> {
62 len += token.len; 62 len += token.len;
63 } 63 }
64 64
65 ParserInput { text, start_offsets, tokens } 65 TextTokenSource { text, start_offsets, tokens }
66 } 66 }
67} 67}
diff --git a/crates/ra_syntax/src/parsing/builder.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs
index cfe3139b8..961a91d41 100644
--- a/crates/ra_syntax/src/parsing/builder.rs
+++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs
@@ -1,26 +1,24 @@
1use std::mem; 1use std::mem;
2 2
3use ra_parser::{TreeSink, ParseError}; 3use ra_parser::{TreeSink, ParseError};
4use rowan::GreenNodeBuilder;
5 4
6use crate::{ 5use crate::{
7 SmolStr, SyntaxError, SyntaxErrorKind, TextUnit, TextRange, 6 SmolStr, SyntaxError, TextUnit, TextRange, SyntaxTreeBuilder,
8 SyntaxKind::{self, *}, 7 SyntaxKind::{self, *},
9 parsing::Token, 8 parsing::Token,
10 syntax_node::{GreenNode, RaTypes}, 9 syntax_node::GreenNode,
11}; 10};
12 11
13/// Bridges the parser with our specific syntax tree representation. 12/// Bridges the parser with our specific syntax tree representation.
14/// 13///
15/// `TreeBuilder` also handles attachment of trivia (whitespace) to nodes. 14/// `TextTreeSink` also handles attachment of trivia (whitespace) to nodes.
16pub(crate) struct TreeBuilder<'a> { 15pub(crate) struct TextTreeSink<'a> {
17 text: &'a str, 16 text: &'a str,
18 tokens: &'a [Token], 17 tokens: &'a [Token],
19 text_pos: TextUnit, 18 text_pos: TextUnit,
20 token_pos: usize, 19 token_pos: usize,
21 state: State, 20 state: State,
22 errors: Vec<SyntaxError>, 21 inner: SyntaxTreeBuilder,
23 inner: GreenNodeBuilder<RaTypes>,
24} 22}
25 23
26enum State { 24enum State {
@@ -29,11 +27,11 @@ enum State {
29 PendingFinish, 27 PendingFinish,
30} 28}
31 29
32impl<'a> TreeSink for TreeBuilder<'a> { 30impl<'a> TreeSink for TextTreeSink<'a> {
33 fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { 31 fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) {
34 match mem::replace(&mut self.state, State::Normal) { 32 match mem::replace(&mut self.state, State::Normal) {
35 State::PendingStart => unreachable!(), 33 State::PendingStart => unreachable!(),
36 State::PendingFinish => self.inner.finish_internal(), 34 State::PendingFinish => self.inner.finish_branch(),
37 State::Normal => (), 35 State::Normal => (),
38 } 36 }
39 self.eat_trivias(); 37 self.eat_trivias();
@@ -48,12 +46,12 @@ impl<'a> TreeSink for TreeBuilder<'a> {
48 fn start_branch(&mut self, kind: SyntaxKind) { 46 fn start_branch(&mut self, kind: SyntaxKind) {
49 match mem::replace(&mut self.state, State::Normal) { 47 match mem::replace(&mut self.state, State::Normal) {
50 State::PendingStart => { 48 State::PendingStart => {
51 self.inner.start_internal(kind); 49 self.inner.start_branch(kind);
52 // No need to attach trivias to previous node: there is no 50 // No need to attach trivias to previous node: there is no
53 // previous node. 51 // previous node.
54 return; 52 return;
55 } 53 }
56 State::PendingFinish => self.inner.finish_internal(), 54 State::PendingFinish => self.inner.finish_branch(),
57 State::Normal => (), 55 State::Normal => (),
58 } 56 }
59 57
@@ -73,34 +71,32 @@ impl<'a> TreeSink for TreeBuilder<'a> {
73 n_attached_trivias(kind, leading_trivias) 71 n_attached_trivias(kind, leading_trivias)
74 }; 72 };
75 self.eat_n_trivias(n_trivias - n_attached_trivias); 73 self.eat_n_trivias(n_trivias - n_attached_trivias);
76 self.inner.start_internal(kind); 74 self.inner.start_branch(kind);
77 self.eat_n_trivias(n_attached_trivias); 75 self.eat_n_trivias(n_attached_trivias);
78 } 76 }
79 77
80 fn finish_branch(&mut self) { 78 fn finish_branch(&mut self) {
81 match mem::replace(&mut self.state, State::PendingFinish) { 79 match mem::replace(&mut self.state, State::PendingFinish) {
82 State::PendingStart => unreachable!(), 80 State::PendingStart => unreachable!(),
83 State::PendingFinish => self.inner.finish_internal(), 81 State::PendingFinish => self.inner.finish_branch(),
84 State::Normal => (), 82 State::Normal => (),
85 } 83 }
86 } 84 }
87 85
88 fn error(&mut self, error: ParseError) { 86 fn error(&mut self, error: ParseError) {
89 let error = SyntaxError::new(SyntaxErrorKind::ParseError(error), self.text_pos); 87 self.inner.error(error, self.text_pos)
90 self.errors.push(error)
91 } 88 }
92} 89}
93 90
94impl<'a> TreeBuilder<'a> { 91impl<'a> TextTreeSink<'a> {
95 pub(super) fn new(text: &'a str, tokens: &'a [Token]) -> TreeBuilder<'a> { 92 pub(super) fn new(text: &'a str, tokens: &'a [Token]) -> TextTreeSink<'a> {
96 TreeBuilder { 93 TextTreeSink {
97 text, 94 text,
98 tokens, 95 tokens,
99 text_pos: 0.into(), 96 text_pos: 0.into(),
100 token_pos: 0, 97 token_pos: 0,
101 state: State::PendingStart, 98 state: State::PendingStart,
102 errors: Vec::new(), 99 inner: SyntaxTreeBuilder::default(),
103 inner: GreenNodeBuilder::new(),
104 } 100 }
105 } 101 }
106 102
@@ -108,12 +104,12 @@ impl<'a> TreeBuilder<'a> {
108 match mem::replace(&mut self.state, State::Normal) { 104 match mem::replace(&mut self.state, State::Normal) {
109 State::PendingFinish => { 105 State::PendingFinish => {
110 self.eat_trivias(); 106 self.eat_trivias();
111 self.inner.finish_internal() 107 self.inner.finish_branch()
112 } 108 }
113 State::PendingStart | State::Normal => unreachable!(), 109 State::PendingStart | State::Normal => unreachable!(),
114 } 110 }
115 111
116 (self.inner.finish(), self.errors) 112 self.inner.finish_raw()
117 } 113 }
118 114
119 fn eat_trivias(&mut self) { 115 fn eat_trivias(&mut self) {
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index 4d54ae614..e5b4cdb11 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -11,11 +11,12 @@ use std::{
11 borrow::Borrow, 11 borrow::Borrow,
12}; 12};
13 13
14use rowan::{Types, TransparentNewType}; 14use ra_parser::ParseError;
15use rowan::{Types, TransparentNewType, GreenNodeBuilder};
15 16
16use crate::{ 17use crate::{
17 SmolStr, SyntaxKind, TextRange, SyntaxText, SourceFile, AstNode, 18 SmolStr, SyntaxKind, TextUnit, TextRange, SyntaxText, SourceFile, AstNode,
18 syntax_error::SyntaxError, 19 syntax_error::{SyntaxError, SyntaxErrorKind},
19}; 20};
20 21
21pub use rowan::WalkEvent; 22pub use rowan::WalkEvent;
@@ -276,3 +277,47 @@ fn has_short_text(kind: SyntaxKind) -> bool {
276 _ => false, 277 _ => false,
277 } 278 }
278} 279}
280
281pub struct SyntaxTreeBuilder {
282 errors: Vec<SyntaxError>,
283 inner: GreenNodeBuilder<RaTypes>,
284}
285
286impl Default for SyntaxTreeBuilder {
287 fn default() -> SyntaxTreeBuilder {
288 SyntaxTreeBuilder { errors: Vec::new(), inner: GreenNodeBuilder::new() }
289 }
290}
291
292impl SyntaxTreeBuilder {
293 pub(crate) fn finish_raw(self) -> (GreenNode, Vec<SyntaxError>) {
294 let green = self.inner.finish();
295 (green, self.errors)
296 }
297
298 pub fn finish(self) -> TreeArc<SyntaxNode> {
299 let (green, errors) = self.finish_raw();
300 let node = SyntaxNode::new(green, errors);
301 if cfg!(debug_assertions) {
302 crate::validation::validate_block_structure(&node);
303 }
304 node
305 }
306
307 pub fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) {
308 self.inner.leaf(kind, text)
309 }
310
311 pub fn start_branch(&mut self, kind: SyntaxKind) {
312 self.inner.start_internal(kind)
313 }
314
315 pub fn finish_branch(&mut self) {
316 self.inner.finish_internal()
317 }
318
319 pub fn error(&mut self, error: ParseError, text_pos: TextUnit) {
320 let error = SyntaxError::new(SyntaxErrorKind::ParseError(error), text_pos);
321 self.errors.push(error)
322 }
323}