diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-10-26 14:08:47 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-26 14:08:47 +0000 |
commit | 1a84cadc88e23fead7435384bfd986dc08081509 (patch) | |
tree | 74c8029d3f0fca58a4ba6734a6361906540e0878 /crates/syntax | |
parent | 29f5154d1c664c8fb1dfae45281873ed97a68a55 (diff) | |
parent | 45860d520786a86007f2f86635b4d2f9c3b0c74e (diff) |
Merge #6347
6347: Support insertion in SyntaxRewriter r=Veykril a=Veykril
Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/algo.rs | 165 |
1 files changed, 141 insertions, 24 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 4f9a7a6e8..065035fe6 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -289,11 +289,19 @@ fn _replace_children( | |||
289 | with_children(parent, new_children) | 289 | with_children(parent, new_children) |
290 | } | 290 | } |
291 | 291 | ||
292 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
293 | enum InsertPos { | ||
294 | FirstChildOf(SyntaxNode), | ||
295 | // Before(SyntaxElement), | ||
296 | After(SyntaxElement), | ||
297 | } | ||
298 | |||
292 | #[derive(Default)] | 299 | #[derive(Default)] |
293 | pub struct SyntaxRewriter<'a> { | 300 | pub struct SyntaxRewriter<'a> { |
294 | f: Option<Box<dyn Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a>>, | 301 | f: Option<Box<dyn Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a>>, |
295 | //FIXME: add debug_assertions that all elements are in fact from the same file. | 302 | //FIXME: add debug_assertions that all elements are in fact from the same file. |
296 | replacements: FxHashMap<SyntaxElement, Replacement>, | 303 | replacements: FxHashMap<SyntaxElement, Replacement>, |
304 | insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, | ||
297 | } | 305 | } |
298 | 306 | ||
299 | impl fmt::Debug for SyntaxRewriter<'_> { | 307 | impl fmt::Debug for SyntaxRewriter<'_> { |
@@ -304,13 +312,96 @@ impl fmt::Debug for SyntaxRewriter<'_> { | |||
304 | 312 | ||
305 | impl<'a> SyntaxRewriter<'a> { | 313 | impl<'a> SyntaxRewriter<'a> { |
306 | pub fn from_fn(f: impl Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a) -> SyntaxRewriter<'a> { | 314 | pub fn from_fn(f: impl Fn(&SyntaxElement) -> Option<SyntaxElement> + 'a) -> SyntaxRewriter<'a> { |
307 | SyntaxRewriter { f: Some(Box::new(f)), replacements: FxHashMap::default() } | 315 | SyntaxRewriter { |
316 | f: Some(Box::new(f)), | ||
317 | replacements: FxHashMap::default(), | ||
318 | insertions: IndexMap::default(), | ||
319 | } | ||
308 | } | 320 | } |
309 | pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) { | 321 | pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) { |
310 | let what = what.clone().into(); | 322 | let what = what.clone().into(); |
311 | let replacement = Replacement::Delete; | 323 | let replacement = Replacement::Delete; |
312 | self.replacements.insert(what, replacement); | 324 | self.replacements.insert(what, replacement); |
313 | } | 325 | } |
326 | pub fn insert_before<T: Clone + Into<SyntaxElement>, U: Clone + Into<SyntaxElement>>( | ||
327 | &mut self, | ||
328 | before: &T, | ||
329 | what: &U, | ||
330 | ) { | ||
331 | let before = before.clone().into(); | ||
332 | let pos = match before.prev_sibling_or_token() { | ||
333 | Some(sibling) => InsertPos::After(sibling), | ||
334 | None => match before.parent() { | ||
335 | Some(parent) => InsertPos::FirstChildOf(parent), | ||
336 | None => return, | ||
337 | }, | ||
338 | }; | ||
339 | self.insertions.entry(pos).or_insert_with(Vec::new).push(what.clone().into()); | ||
340 | } | ||
341 | pub fn insert_after<T: Clone + Into<SyntaxElement>, U: Clone + Into<SyntaxElement>>( | ||
342 | &mut self, | ||
343 | after: &T, | ||
344 | what: &U, | ||
345 | ) { | ||
346 | self.insertions | ||
347 | .entry(InsertPos::After(after.clone().into())) | ||
348 | .or_insert_with(Vec::new) | ||
349 | .push(what.clone().into()); | ||
350 | } | ||
351 | pub fn insert_as_first_child<T: Clone + Into<SyntaxNode>, U: Clone + Into<SyntaxElement>>( | ||
352 | &mut self, | ||
353 | parent: &T, | ||
354 | what: &U, | ||
355 | ) { | ||
356 | self.insertions | ||
357 | .entry(InsertPos::FirstChildOf(parent.clone().into())) | ||
358 | .or_insert_with(Vec::new) | ||
359 | .push(what.clone().into()); | ||
360 | } | ||
361 | pub fn insert_many_before< | ||
362 | T: Clone + Into<SyntaxElement>, | ||
363 | U: IntoIterator<Item = SyntaxElement>, | ||
364 | >( | ||
365 | &mut self, | ||
366 | before: &T, | ||
367 | what: U, | ||
368 | ) { | ||
369 | let before = before.clone().into(); | ||
370 | let pos = match before.prev_sibling_or_token() { | ||
371 | Some(sibling) => InsertPos::After(sibling), | ||
372 | None => match before.parent() { | ||
373 | Some(parent) => InsertPos::FirstChildOf(parent), | ||
374 | None => return, | ||
375 | }, | ||
376 | }; | ||
377 | self.insertions.entry(pos).or_insert_with(Vec::new).extend(what); | ||
378 | } | ||
379 | pub fn insert_many_after< | ||
380 | T: Clone + Into<SyntaxElement>, | ||
381 | U: IntoIterator<Item = SyntaxElement>, | ||
382 | >( | ||
383 | &mut self, | ||
384 | after: &T, | ||
385 | what: U, | ||
386 | ) { | ||
387 | self.insertions | ||
388 | .entry(InsertPos::After(after.clone().into())) | ||
389 | .or_insert_with(Vec::new) | ||
390 | .extend(what); | ||
391 | } | ||
392 | pub fn insert_many_as_first_children< | ||
393 | T: Clone + Into<SyntaxNode>, | ||
394 | U: IntoIterator<Item = SyntaxElement>, | ||
395 | >( | ||
396 | &mut self, | ||
397 | parent: &T, | ||
398 | what: U, | ||
399 | ) { | ||
400 | self.insertions | ||
401 | .entry(InsertPos::FirstChildOf(parent.clone().into())) | ||
402 | .or_insert_with(Vec::new) | ||
403 | .extend(what) | ||
404 | } | ||
314 | pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { | 405 | pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { |
315 | let what = what.clone().into(); | 406 | let what = what.clone().into(); |
316 | let replacement = Replacement::Single(with.clone().into()); | 407 | let replacement = Replacement::Single(with.clone().into()); |
@@ -330,7 +421,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
330 | } | 421 | } |
331 | 422 | ||
332 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { | 423 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { |
333 | if self.f.is_none() && self.replacements.is_empty() { | 424 | if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() { |
334 | return node.clone(); | 425 | return node.clone(); |
335 | } | 426 | } |
336 | self.rewrite_children(node) | 427 | self.rewrite_children(node) |
@@ -346,14 +437,22 @@ impl<'a> SyntaxRewriter<'a> { | |||
346 | /// | 437 | /// |
347 | /// Returns `None` when there are no replacements. | 438 | /// Returns `None` when there are no replacements. |
348 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { | 439 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { |
440 | fn element_to_node_or_parent(element: &SyntaxElement) -> SyntaxNode { | ||
441 | match element { | ||
442 | SyntaxElement::Node(it) => it.clone(), | ||
443 | SyntaxElement::Token(it) => it.parent(), | ||
444 | } | ||
445 | } | ||
446 | |||
349 | assert!(self.f.is_none()); | 447 | assert!(self.f.is_none()); |
350 | self.replacements | 448 | self.replacements |
351 | .keys() | 449 | .keys() |
352 | .map(|element| match element { | 450 | .map(element_to_node_or_parent) |
353 | SyntaxElement::Node(it) => it.clone(), | 451 | .chain(self.insertions.keys().map(|pos| match pos { |
354 | SyntaxElement::Token(it) => it.parent(), | 452 | InsertPos::FirstChildOf(it) => it.clone(), |
355 | }) | 453 | InsertPos::After(it) => element_to_node_or_parent(it), |
356 | // If we only have one replacement, we must return its parent node, since `rewrite` does | 454 | })) |
455 | // If we only have one replacement/insertion, we must return its parent node, since `rewrite` does | ||
357 | // not replace the node passed to it. | 456 | // not replace the node passed to it. |
358 | .map(|it| it.parent().unwrap_or(it)) | 457 | .map(|it| it.parent().unwrap_or(it)) |
359 | .fold1(|a, b| least_common_ancestor(&a, &b).unwrap()) | 458 | .fold1(|a, b| least_common_ancestor(&a, &b).unwrap()) |
@@ -367,9 +466,16 @@ impl<'a> SyntaxRewriter<'a> { | |||
367 | self.replacements.get(element).cloned() | 466 | self.replacements.get(element).cloned() |
368 | } | 467 | } |
369 | 468 | ||
469 | fn insertions(&self, pos: &InsertPos) -> Option<impl Iterator<Item = SyntaxElement> + '_> { | ||
470 | self.insertions.get(pos).map(|insertions| insertions.iter().cloned()) | ||
471 | } | ||
472 | |||
370 | fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode { | 473 | fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode { |
371 | // FIXME: this could be made much faster. | 474 | // FIXME: this could be made much faster. |
372 | let mut new_children = Vec::new(); | 475 | let mut new_children = Vec::new(); |
476 | if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) { | ||
477 | new_children.extend(elements.map(element_to_green)); | ||
478 | } | ||
373 | for child in node.children_with_tokens() { | 479 | for child in node.children_with_tokens() { |
374 | self.rewrite_self(&mut new_children, &child); | 480 | self.rewrite_self(&mut new_children, &child); |
375 | } | 481 | } |
@@ -383,34 +489,45 @@ impl<'a> SyntaxRewriter<'a> { | |||
383 | ) { | 489 | ) { |
384 | if let Some(replacement) = self.replacement(&element) { | 490 | if let Some(replacement) = self.replacement(&element) { |
385 | match replacement { | 491 | match replacement { |
386 | Replacement::Single(NodeOrToken::Node(it)) => { | 492 | Replacement::Single(element) => acc.push(element_to_green(element)), |
387 | acc.push(NodeOrToken::Node(it.green().clone())) | ||
388 | } | ||
389 | Replacement::Single(NodeOrToken::Token(it)) => { | ||
390 | acc.push(NodeOrToken::Token(it.green().clone())) | ||
391 | } | ||
392 | Replacement::Many(replacements) => { | 493 | Replacement::Many(replacements) => { |
393 | acc.extend(replacements.iter().map(|it| match it { | 494 | acc.extend(replacements.into_iter().map(element_to_green)) |
394 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().clone()), | ||
395 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | ||
396 | })) | ||
397 | } | 495 | } |
398 | Replacement::Delete => (), | 496 | Replacement::Delete => (), |
399 | }; | 497 | }; |
400 | return; | 498 | } else { |
499 | match element { | ||
500 | NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().clone())), | ||
501 | NodeOrToken::Node(it) => { | ||
502 | acc.push(NodeOrToken::Node(self.rewrite_children(it).green().clone())); | ||
503 | } | ||
504 | } | ||
505 | } | ||
506 | if let Some(elements) = self.insertions(&InsertPos::After(element.clone())) { | ||
507 | acc.extend(elements.map(element_to_green)); | ||
401 | } | 508 | } |
402 | let res = match element { | 509 | } |
403 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | 510 | } |
404 | NodeOrToken::Node(it) => NodeOrToken::Node(self.rewrite_children(it).green().clone()), | 511 | |
405 | }; | 512 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
406 | acc.push(res) | 513 | match element { |
514 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().clone()), | ||
515 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | ||
407 | } | 516 | } |
408 | } | 517 | } |
409 | 518 | ||
410 | impl ops::AddAssign for SyntaxRewriter<'_> { | 519 | impl ops::AddAssign for SyntaxRewriter<'_> { |
411 | fn add_assign(&mut self, rhs: SyntaxRewriter) { | 520 | fn add_assign(&mut self, rhs: SyntaxRewriter) { |
412 | assert!(rhs.f.is_none()); | 521 | assert!(rhs.f.is_none()); |
413 | self.replacements.extend(rhs.replacements) | 522 | self.replacements.extend(rhs.replacements); |
523 | for (pos, insertions) in rhs.insertions.into_iter() { | ||
524 | match self.insertions.entry(pos) { | ||
525 | indexmap::map::Entry::Occupied(mut occupied) => { | ||
526 | occupied.get_mut().extend(insertions) | ||
527 | } | ||
528 | indexmap::map::Entry::Vacant(vacant) => drop(vacant.insert(insertions)), | ||
529 | } | ||
530 | } | ||
414 | } | 531 | } |
415 | } | 532 | } |
416 | 533 | ||