diff options
author | Lukas Wirth <[email protected]> | 2020-10-24 19:53:16 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2020-10-24 19:53:16 +0100 |
commit | aca2735d1e1589dd474858f4cef9ef638d741e5b (patch) | |
tree | 25e08ef466ed8b6f023a9f123f1767a253975742 /crates/syntax | |
parent | d5c294f78ca9c621e38b23102e3b5ca1bdd175f3 (diff) |
Support insertion in SyntaxRewriter
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/algo.rs | 158 |
1 files changed, 134 insertions, 24 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 4f9a7a6e8..0baae2f57 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,86 @@ 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 | self.insertions | ||
332 | .entry(InsertPos::Before(before.clone().into())) | ||
333 | .or_insert_with(Vec::new) | ||
334 | .push(what.clone().into()); | ||
335 | } | ||
336 | pub fn insert_after<T: Clone + Into<SyntaxElement>, U: Clone + Into<SyntaxElement>>( | ||
337 | &mut self, | ||
338 | after: &T, | ||
339 | what: &U, | ||
340 | ) { | ||
341 | self.insertions | ||
342 | .entry(InsertPos::After(after.clone().into())) | ||
343 | .or_insert_with(Vec::new) | ||
344 | .push(what.clone().into()); | ||
345 | } | ||
346 | pub fn insert_as_first_child<T: Clone + Into<SyntaxNode>, U: Clone + Into<SyntaxElement>>( | ||
347 | &mut self, | ||
348 | parent: &T, | ||
349 | what: &U, | ||
350 | ) { | ||
351 | self.insertions | ||
352 | .entry(InsertPos::FirstChildOf(parent.clone().into())) | ||
353 | .or_insert_with(Vec::new) | ||
354 | .push(what.clone().into()); | ||
355 | } | ||
356 | pub fn insert_many_before< | ||
357 | T: Clone + Into<SyntaxElement>, | ||
358 | U: IntoIterator<Item = SyntaxElement>, | ||
359 | >( | ||
360 | &mut self, | ||
361 | before: &T, | ||
362 | what: U, | ||
363 | ) { | ||
364 | self.insertions | ||
365 | .entry(InsertPos::Before(before.clone().into())) | ||
366 | .or_insert_with(Vec::new) | ||
367 | .extend(what); | ||
368 | } | ||
369 | pub fn insert_many_after< | ||
370 | T: Clone + Into<SyntaxElement>, | ||
371 | U: IntoIterator<Item = SyntaxElement>, | ||
372 | >( | ||
373 | &mut self, | ||
374 | after: &T, | ||
375 | what: U, | ||
376 | ) { | ||
377 | self.insertions | ||
378 | .entry(InsertPos::After(after.clone().into())) | ||
379 | .or_insert_with(Vec::new) | ||
380 | .extend(what); | ||
381 | } | ||
382 | pub fn insert_many_as_first_children< | ||
383 | T: Clone + Into<SyntaxNode>, | ||
384 | U: IntoIterator<Item = SyntaxElement>, | ||
385 | >( | ||
386 | &mut self, | ||
387 | parent: &T, | ||
388 | what: U, | ||
389 | ) { | ||
390 | self.insertions | ||
391 | .entry(InsertPos::FirstChildOf(parent.clone().into())) | ||
392 | .or_insert_with(Vec::new) | ||
393 | .extend(what) | ||
394 | } | ||
314 | pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { | 395 | pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { |
315 | let what = what.clone().into(); | 396 | let what = what.clone().into(); |
316 | let replacement = Replacement::Single(with.clone().into()); | 397 | let replacement = Replacement::Single(with.clone().into()); |
@@ -330,7 +411,7 @@ impl<'a> SyntaxRewriter<'a> { | |||
330 | } | 411 | } |
331 | 412 | ||
332 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { | 413 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { |
333 | if self.f.is_none() && self.replacements.is_empty() { | 414 | if self.f.is_none() && self.replacements.is_empty() && self.insertions.is_empty() { |
334 | return node.clone(); | 415 | return node.clone(); |
335 | } | 416 | } |
336 | self.rewrite_children(node) | 417 | self.rewrite_children(node) |
@@ -346,14 +427,22 @@ impl<'a> SyntaxRewriter<'a> { | |||
346 | /// | 427 | /// |
347 | /// Returns `None` when there are no replacements. | 428 | /// Returns `None` when there are no replacements. |
348 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { | 429 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { |
430 | fn element_to_node_or_parent(element: &SyntaxElement) -> SyntaxNode { | ||
431 | match element { | ||
432 | SyntaxElement::Node(it) => it.clone(), | ||
433 | SyntaxElement::Token(it) => it.parent(), | ||
434 | } | ||
435 | } | ||
436 | |||
349 | assert!(self.f.is_none()); | 437 | assert!(self.f.is_none()); |
350 | self.replacements | 438 | self.replacements |
351 | .keys() | 439 | .keys() |
352 | .map(|element| match element { | 440 | .map(element_to_node_or_parent) |
353 | SyntaxElement::Node(it) => it.clone(), | 441 | .chain(self.insertions.keys().map(|pos| match pos { |
354 | SyntaxElement::Token(it) => it.parent(), | 442 | InsertPos::FirstChildOf(it) => it.clone(), |
355 | }) | 443 | InsertPos::Before(it) | 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 | 444 | })) |
445 | // If we only have one replacement/insertion, we must return its parent node, since `rewrite` does | ||
357 | // not replace the node passed to it. | 446 | // not replace the node passed to it. |
358 | .map(|it| it.parent().unwrap_or(it)) | 447 | .map(|it| it.parent().unwrap_or(it)) |
359 | .fold1(|a, b| least_common_ancestor(&a, &b).unwrap()) | 448 | .fold1(|a, b| least_common_ancestor(&a, &b).unwrap()) |
@@ -367,9 +456,16 @@ impl<'a> SyntaxRewriter<'a> { | |||
367 | self.replacements.get(element).cloned() | 456 | self.replacements.get(element).cloned() |
368 | } | 457 | } |
369 | 458 | ||
459 | fn insertions(&self, pos: &InsertPos) -> Option<impl Iterator<Item = SyntaxElement> + '_> { | ||
460 | self.insertions.get(pos).map(|insertions| insertions.iter().cloned()) | ||
461 | } | ||
462 | |||
370 | fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode { | 463 | fn rewrite_children(&self, node: &SyntaxNode) -> SyntaxNode { |
371 | // FIXME: this could be made much faster. | 464 | // FIXME: this could be made much faster. |
372 | let mut new_children = Vec::new(); | 465 | let mut new_children = Vec::new(); |
466 | if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) { | ||
467 | new_children.extend(elements.map(element_to_green)); | ||
468 | } | ||
373 | for child in node.children_with_tokens() { | 469 | for child in node.children_with_tokens() { |
374 | self.rewrite_self(&mut new_children, &child); | 470 | self.rewrite_self(&mut new_children, &child); |
375 | } | 471 | } |
@@ -381,36 +477,50 @@ impl<'a> SyntaxRewriter<'a> { | |||
381 | acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, | 477 | acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, |
382 | element: &SyntaxElement, | 478 | element: &SyntaxElement, |
383 | ) { | 479 | ) { |
480 | if let Some(elements) = self.insertions(&InsertPos::Before(element.clone())) { | ||
481 | acc.extend(elements.map(element_to_green)); | ||
482 | } | ||
384 | if let Some(replacement) = self.replacement(&element) { | 483 | if let Some(replacement) = self.replacement(&element) { |
385 | match replacement { | 484 | match replacement { |
386 | Replacement::Single(NodeOrToken::Node(it)) => { | 485 | 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) => { | 486 | Replacement::Many(replacements) => { |
393 | acc.extend(replacements.iter().map(|it| match it { | 487 | 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 | } | 488 | } |
398 | Replacement::Delete => (), | 489 | Replacement::Delete => (), |
399 | }; | 490 | }; |
400 | return; | 491 | } else { |
492 | match element { | ||
493 | NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().clone())), | ||
494 | NodeOrToken::Node(it) => { | ||
495 | acc.push(NodeOrToken::Node(self.rewrite_children(it).green().clone())); | ||
496 | } | ||
497 | } | ||
401 | } | 498 | } |
402 | let res = match element { | 499 | if let Some(elements) = self.insertions(&InsertPos::After(element.clone())) { |
403 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | 500 | acc.extend(elements.map(element_to_green)); |
404 | NodeOrToken::Node(it) => NodeOrToken::Node(self.rewrite_children(it).green().clone()), | 501 | } |
405 | }; | 502 | } |
406 | acc.push(res) | 503 | } |
504 | |||
505 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | ||
506 | match element { | ||
507 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().clone()), | ||
508 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | ||
407 | } | 509 | } |
408 | } | 510 | } |
409 | 511 | ||
410 | impl ops::AddAssign for SyntaxRewriter<'_> { | 512 | impl ops::AddAssign for SyntaxRewriter<'_> { |
411 | fn add_assign(&mut self, rhs: SyntaxRewriter) { | 513 | fn add_assign(&mut self, rhs: SyntaxRewriter) { |
412 | assert!(rhs.f.is_none()); | 514 | assert!(rhs.f.is_none()); |
413 | self.replacements.extend(rhs.replacements) | 515 | self.replacements.extend(rhs.replacements); |
516 | for (pos, insertions) in rhs.insertions.into_iter() { | ||
517 | match self.insertions.entry(pos) { | ||
518 | indexmap::map::Entry::Occupied(mut occupied) => { | ||
519 | occupied.get_mut().extend(insertions) | ||
520 | } | ||
521 | indexmap::map::Entry::Vacant(vacant) => drop(vacant.insert(insertions)), | ||
522 | } | ||
523 | } | ||
414 | } | 524 | } |
415 | } | 525 | } |
416 | 526 | ||