diff options
Diffstat (limited to 'crates/ra_syntax/src/reparsing.rs')
-rw-r--r-- | crates/ra_syntax/src/reparsing.rs | 247 |
1 files changed, 152 insertions, 95 deletions
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs index 16272fe88..a0014e016 100644 --- a/crates/ra_syntax/src/reparsing.rs +++ b/crates/ra_syntax/src/reparsing.rs | |||
@@ -1,14 +1,11 @@ | |||
1 | use crate::algo; | 1 | use crate::algo; |
2 | use crate::grammar; | 2 | use crate::grammar; |
3 | use crate::lexer::{tokenize, Token}; | 3 | use crate::lexer::{tokenize, Token}; |
4 | use crate::yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError}; | ||
5 | use crate::parser_impl; | ||
6 | use crate::parser_api::Parser; | 4 | use crate::parser_api::Parser; |
7 | use crate::{ | 5 | use crate::parser_impl; |
8 | TextUnit, TextRange, | ||
9 | SyntaxKind::*, | ||
10 | }; | ||
11 | use crate::text_utils::replace_range; | 6 | use crate::text_utils::replace_range; |
7 | use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNodeRef}; | ||
8 | use crate::{SyntaxKind::*, TextRange, TextUnit}; | ||
12 | 9 | ||
13 | #[derive(Debug, Clone)] | 10 | #[derive(Debug, Clone)] |
14 | pub struct AtomEdit { | 11 | pub struct AtomEdit { |
@@ -18,7 +15,10 @@ pub struct AtomEdit { | |||
18 | 15 | ||
19 | impl AtomEdit { | 16 | impl AtomEdit { |
20 | pub fn replace(range: TextRange, replace_with: String) -> AtomEdit { | 17 | pub fn replace(range: TextRange, replace_with: String) -> AtomEdit { |
21 | AtomEdit { delete: range, insert: replace_with } | 18 | AtomEdit { |
19 | delete: range, | ||
20 | insert: replace_with, | ||
21 | } | ||
22 | } | 22 | } |
23 | 23 | ||
24 | pub fn delete(range: TextRange) -> AtomEdit { | 24 | pub fn delete(range: TextRange) -> AtomEdit { |
@@ -48,12 +48,7 @@ fn reparse_leaf<'node>( | |||
48 | ) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> { | 48 | ) -> Option<(SyntaxNodeRef<'node>, GreenNode, Vec<SyntaxError>)> { |
49 | let node = algo::find_covering_node(node, edit.delete); | 49 | let node = algo::find_covering_node(node, edit.delete); |
50 | match node.kind() { | 50 | match node.kind() { |
51 | | WHITESPACE | 51 | WHITESPACE | COMMENT | DOC_COMMENT | IDENT | STRING | RAW_STRING => { |
52 | | COMMENT | ||
53 | | DOC_COMMENT | ||
54 | | IDENT | ||
55 | | STRING | ||
56 | | RAW_STRING => { | ||
57 | let text = get_text_after_edit(node, &edit); | 52 | let text = get_text_after_edit(node, &edit); |
58 | let tokens = tokenize(&text); | 53 | let tokens = tokenize(&text); |
59 | let token = match tokens[..] { | 54 | let token = match tokens[..] { |
@@ -84,10 +79,7 @@ fn reparse_block<'node>( | |||
84 | return None; | 79 | return None; |
85 | } | 80 | } |
86 | let (green, new_errors) = | 81 | let (green, new_errors) = |
87 | parser_impl::parse_with( | 82 | parser_impl::parse_with(yellow::GreenBuilder::new(), &text, &tokens, reparser); |
88 | yellow::GreenBuilder::new(), | ||
89 | &text, &tokens, reparser, | ||
90 | ); | ||
91 | Some((node, green, new_errors)) | 83 | Some((node, green, new_errors)) |
92 | } | 84 | } |
93 | 85 | ||
@@ -101,9 +93,7 @@ fn get_text_after_edit(node: SyntaxNodeRef, edit: &AtomEdit) -> String { | |||
101 | 93 | ||
102 | fn is_contextual_kw(text: &str) -> bool { | 94 | fn is_contextual_kw(text: &str) -> bool { |
103 | match text { | 95 | match text { |
104 | | "auto" | 96 | "auto" | "default" | "union" => true, |
105 | | "default" | ||
106 | | "union" => true, | ||
107 | _ => false, | 97 | _ => false, |
108 | } | 98 | } |
109 | } | 99 | } |
@@ -113,7 +103,8 @@ fn find_reparsable_node<'node>( | |||
113 | range: TextRange, | 103 | range: TextRange, |
114 | ) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> { | 104 | ) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> { |
115 | let node = algo::find_covering_node(node, range); | 105 | let node = algo::find_covering_node(node, range); |
116 | return node.ancestors() | 106 | return node |
107 | .ancestors() | ||
117 | .filter_map(|node| reparser(node).map(|r| (node, r))) | 108 | .filter_map(|node| reparser(node).map(|r| (node, r))) |
118 | .next(); | 109 | .next(); |
119 | 110 | ||
@@ -145,17 +136,20 @@ fn find_reparsable_node<'node>( | |||
145 | fn is_balanced(tokens: &[Token]) -> bool { | 136 | fn is_balanced(tokens: &[Token]) -> bool { |
146 | if tokens.len() == 0 | 137 | if tokens.len() == 0 |
147 | || tokens.first().unwrap().kind != L_CURLY | 138 | || tokens.first().unwrap().kind != L_CURLY |
148 | || tokens.last().unwrap().kind != R_CURLY { | 139 | || tokens.last().unwrap().kind != R_CURLY |
140 | { | ||
149 | return false; | 141 | return false; |
150 | } | 142 | } |
151 | let mut balance = 0usize; | 143 | let mut balance = 0usize; |
152 | for t in tokens.iter() { | 144 | for t in tokens.iter() { |
153 | match t.kind { | 145 | match t.kind { |
154 | L_CURLY => balance += 1, | 146 | L_CURLY => balance += 1, |
155 | R_CURLY => balance = match balance.checked_sub(1) { | 147 | R_CURLY => { |
156 | Some(b) => b, | 148 | balance = match balance.checked_sub(1) { |
157 | None => return false, | 149 | Some(b) => b, |
158 | }, | 150 | None => return false, |
151 | } | ||
152 | } | ||
159 | _ => (), | 153 | _ => (), |
160 | } | 154 | } |
161 | } | 155 | } |
@@ -191,24 +185,14 @@ fn merge_errors( | |||
191 | #[cfg(test)] | 185 | #[cfg(test)] |
192 | mod tests { | 186 | mod tests { |
193 | use super::{ | 187 | use super::{ |
194 | super::{ | 188 | super::{test_utils::extract_range, text_utils::replace_range, utils::dump_tree, File}, |
195 | File, | 189 | reparse_block, reparse_leaf, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef, |
196 | test_utils::extract_range, | ||
197 | text_utils::replace_range, | ||
198 | utils::dump_tree, | ||
199 | }, | ||
200 | reparse_leaf, reparse_block, AtomEdit, GreenNode, SyntaxError, SyntaxNodeRef, | ||
201 | }; | 190 | }; |
202 | 191 | ||
203 | fn do_check<F>( | 192 | fn do_check<F>(before: &str, replace_with: &str, reparser: F) |
204 | before: &str, | 193 | where |
205 | replace_with: &str, | 194 | for<'a> F: Fn(SyntaxNodeRef<'a>, &AtomEdit) |
206 | reparser: F, | 195 | -> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)>, |
207 | ) where | ||
208 | for<'a> F: Fn( | ||
209 | SyntaxNodeRef<'a>, | ||
210 | &AtomEdit, | ||
211 | ) -> Option<(SyntaxNodeRef<'a>, GreenNode, Vec<SyntaxError>)> | ||
212 | { | 196 | { |
213 | let (range, before) = extract_range(before); | 197 | let (range, before) = extract_range(before); |
214 | let after = replace_range(before.clone(), range, replace_with); | 198 | let after = replace_range(before.clone(), range, replace_with); |
@@ -216,7 +200,10 @@ mod tests { | |||
216 | let fully_reparsed = File::parse(&after); | 200 | let fully_reparsed = File::parse(&after); |
217 | let incrementally_reparsed = { | 201 | let incrementally_reparsed = { |
218 | let f = File::parse(&before); | 202 | let f = File::parse(&before); |
219 | let edit = AtomEdit { delete: range, insert: replace_with.to_string() }; | 203 | let edit = AtomEdit { |
204 | delete: range, | ||
205 | insert: replace_with.to_string(), | ||
206 | }; | ||
220 | let (node, green, new_errors) = | 207 | let (node, green, new_errors) = |
221 | reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); | 208 | reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); |
222 | let green_root = node.replace_with(green); | 209 | let green_root = node.replace_with(green); |
@@ -232,113 +219,183 @@ mod tests { | |||
232 | 219 | ||
233 | #[test] | 220 | #[test] |
234 | fn reparse_block_tests() { | 221 | fn reparse_block_tests() { |
235 | let do_check = |before, replace_to| | 222 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_block); |
236 | do_check(before, replace_to, reparse_block); | ||
237 | 223 | ||
238 | do_check(r" | 224 | do_check( |
225 | r" | ||
239 | fn foo() { | 226 | fn foo() { |
240 | let x = foo + <|>bar<|> | 227 | let x = foo + <|>bar<|> |
241 | } | 228 | } |
242 | ", "baz"); | 229 | ", |
243 | do_check(r" | 230 | "baz", |
231 | ); | ||
232 | do_check( | ||
233 | r" | ||
244 | fn foo() { | 234 | fn foo() { |
245 | let x = foo<|> + bar<|> | 235 | let x = foo<|> + bar<|> |
246 | } | 236 | } |
247 | ", "baz"); | 237 | ", |
248 | do_check(r" | 238 | "baz", |
239 | ); | ||
240 | do_check( | ||
241 | r" | ||
249 | struct Foo { | 242 | struct Foo { |
250 | f: foo<|><|> | 243 | f: foo<|><|> |
251 | } | 244 | } |
252 | ", ",\n g: (),"); | 245 | ", |
253 | do_check(r" | 246 | ",\n g: (),", |
247 | ); | ||
248 | do_check( | ||
249 | r" | ||
254 | fn foo { | 250 | fn foo { |
255 | let; | 251 | let; |
256 | 1 + 1; | 252 | 1 + 1; |
257 | <|>92<|>; | 253 | <|>92<|>; |
258 | } | 254 | } |
259 | ", "62"); | 255 | ", |
260 | do_check(r" | 256 | "62", |
257 | ); | ||
258 | do_check( | ||
259 | r" | ||
261 | mod foo { | 260 | mod foo { |
262 | fn <|><|> | 261 | fn <|><|> |
263 | } | 262 | } |
264 | ", "bar"); | 263 | ", |
265 | do_check(r" | 264 | "bar", |
265 | ); | ||
266 | do_check( | ||
267 | r" | ||
266 | trait Foo { | 268 | trait Foo { |
267 | type <|>Foo<|>; | 269 | type <|>Foo<|>; |
268 | } | 270 | } |
269 | ", "Output"); | 271 | ", |
270 | do_check(r" | 272 | "Output", |
273 | ); | ||
274 | do_check( | ||
275 | r" | ||
271 | impl IntoIterator<Item=i32> for Foo { | 276 | impl IntoIterator<Item=i32> for Foo { |
272 | f<|><|> | 277 | f<|><|> |
273 | } | 278 | } |
274 | ", "n next("); | 279 | ", |
275 | do_check(r" | 280 | "n next(", |
281 | ); | ||
282 | do_check( | ||
283 | r" | ||
276 | use a::b::{foo,<|>,bar<|>}; | 284 | use a::b::{foo,<|>,bar<|>}; |
277 | ", "baz"); | 285 | ", |
278 | do_check(r" | 286 | "baz", |
287 | ); | ||
288 | do_check( | ||
289 | r" | ||
279 | pub enum A { | 290 | pub enum A { |
280 | Foo<|><|> | 291 | Foo<|><|> |
281 | } | 292 | } |
282 | ", "\nBar;\n"); | 293 | ", |
283 | do_check(r" | 294 | "\nBar;\n", |
295 | ); | ||
296 | do_check( | ||
297 | r" | ||
284 | foo!{a, b<|><|> d} | 298 | foo!{a, b<|><|> d} |
285 | ", ", c[3]"); | 299 | ", |
286 | do_check(r" | 300 | ", c[3]", |
301 | ); | ||
302 | do_check( | ||
303 | r" | ||
287 | fn foo() { | 304 | fn foo() { |
288 | vec![<|><|>] | 305 | vec![<|><|>] |
289 | } | 306 | } |
290 | ", "123"); | 307 | ", |
291 | do_check(r" | 308 | "123", |
309 | ); | ||
310 | do_check( | ||
311 | r" | ||
292 | extern { | 312 | extern { |
293 | fn<|>;<|> | 313 | fn<|>;<|> |
294 | } | 314 | } |
295 | ", " exit(code: c_int)"); | 315 | ", |
316 | " exit(code: c_int)", | ||
317 | ); | ||
296 | } | 318 | } |
297 | 319 | ||
298 | #[test] | 320 | #[test] |
299 | fn reparse_leaf_tests() { | 321 | fn reparse_leaf_tests() { |
300 | let do_check = |before, replace_to| | 322 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf); |
301 | do_check(before, replace_to, reparse_leaf); | ||
302 | 323 | ||
303 | do_check(r"<|><|> | 324 | do_check( |
325 | r"<|><|> | ||
304 | fn foo() -> i32 { 1 } | 326 | fn foo() -> i32 { 1 } |
305 | ", "\n\n\n \n"); | 327 | ", |
306 | do_check(r" | 328 | "\n\n\n \n", |
329 | ); | ||
330 | do_check( | ||
331 | r" | ||
307 | fn foo() -> <|><|> {} | 332 | fn foo() -> <|><|> {} |
308 | ", " \n"); | 333 | ", |
309 | do_check(r" | 334 | " \n", |
335 | ); | ||
336 | do_check( | ||
337 | r" | ||
310 | fn <|>foo<|>() -> i32 { 1 } | 338 | fn <|>foo<|>() -> i32 { 1 } |
311 | ", "bar"); | 339 | ", |
312 | do_check(r" | 340 | "bar", |
341 | ); | ||
342 | do_check( | ||
343 | r" | ||
313 | fn foo<|><|>foo() { } | 344 | fn foo<|><|>foo() { } |
314 | ", "bar"); | 345 | ", |
315 | do_check(r" | 346 | "bar", |
347 | ); | ||
348 | do_check( | ||
349 | r" | ||
316 | fn foo /* <|><|> */ () {} | 350 | fn foo /* <|><|> */ () {} |
317 | ", "some comment"); | 351 | ", |
318 | do_check(r" | 352 | "some comment", |
353 | ); | ||
354 | do_check( | ||
355 | r" | ||
319 | fn baz <|><|> () {} | 356 | fn baz <|><|> () {} |
320 | ", " \t\t\n\n"); | 357 | ", |
321 | do_check(r" | 358 | " \t\t\n\n", |
359 | ); | ||
360 | do_check( | ||
361 | r" | ||
322 | fn baz <|><|> () {} | 362 | fn baz <|><|> () {} |
323 | ", " \t\t\n\n"); | 363 | ", |
324 | do_check(r" | 364 | " \t\t\n\n", |
365 | ); | ||
366 | do_check( | ||
367 | r" | ||
325 | /// foo <|><|>omment | 368 | /// foo <|><|>omment |
326 | mod { } | 369 | mod { } |
327 | ", "c"); | 370 | ", |
328 | do_check(r#" | 371 | "c", |
372 | ); | ||
373 | do_check( | ||
374 | r#" | ||
329 | fn -> &str { "Hello<|><|>" } | 375 | fn -> &str { "Hello<|><|>" } |
330 | "#, ", world"); | 376 | "#, |
331 | do_check(r#" | 377 | ", world", |
378 | ); | ||
379 | do_check( | ||
380 | r#" | ||
332 | fn -> &str { // "Hello<|><|>" | 381 | fn -> &str { // "Hello<|><|>" |
333 | "#, ", world"); | 382 | "#, |
334 | do_check(r##" | 383 | ", world", |
384 | ); | ||
385 | do_check( | ||
386 | r##" | ||
335 | fn -> &str { r#"Hello<|><|>"# | 387 | fn -> &str { r#"Hello<|><|>"# |
336 | "##, ", world"); | 388 | "##, |
337 | do_check(r" | 389 | ", world", |
390 | ); | ||
391 | do_check( | ||
392 | r" | ||
338 | #[derive(<|>Copy<|>)] | 393 | #[derive(<|>Copy<|>)] |
339 | enum Foo { | 394 | enum Foo { |
340 | 395 | ||
341 | } | 396 | } |
342 | ", "Clone"); | 397 | ", |
398 | "Clone", | ||
399 | ); | ||
343 | } | 400 | } |
344 | } | 401 | } |