diff options
Diffstat (limited to 'crates/syntax/src/algo.rs')
-rw-r--r-- | crates/syntax/src/algo.rs | 133 |
1 files changed, 1 insertions, 132 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index 3f9b84ab9..241713c48 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{fmt, hash::BuildHasherDefault, ops::RangeInclusive}; | 3 | use std::{hash::BuildHasherDefault, ops::RangeInclusive}; |
4 | 4 | ||
5 | use indexmap::IndexMap; | 5 | use indexmap::IndexMap; |
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
@@ -330,137 +330,6 @@ fn _replace_children( | |||
330 | with_children(parent, new_children) | 330 | with_children(parent, new_children) |
331 | } | 331 | } |
332 | 332 | ||
333 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
334 | enum InsertPos { | ||
335 | FirstChildOf(SyntaxNode), | ||
336 | After(SyntaxElement), | ||
337 | } | ||
338 | |||
339 | #[derive(Default)] | ||
340 | pub struct SyntaxRewriter<'a> { | ||
341 | //FIXME: add debug_assertions that all elements are in fact from the same file. | ||
342 | replacements: FxHashMap<SyntaxElement, Replacement>, | ||
343 | insertions: IndexMap<InsertPos, Vec<SyntaxElement>>, | ||
344 | _pd: std::marker::PhantomData<&'a ()>, | ||
345 | } | ||
346 | |||
347 | impl fmt::Debug for SyntaxRewriter<'_> { | ||
348 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
349 | f.debug_struct("SyntaxRewriter") | ||
350 | .field("replacements", &self.replacements) | ||
351 | .field("insertions", &self.insertions) | ||
352 | .finish() | ||
353 | } | ||
354 | } | ||
355 | |||
356 | impl SyntaxRewriter<'_> { | ||
357 | pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { | ||
358 | let what = what.clone().into(); | ||
359 | let replacement = Replacement::Single(with.clone().into()); | ||
360 | self.replacements.insert(what, replacement); | ||
361 | } | ||
362 | |||
363 | pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { | ||
364 | let _p = profile::span("rewrite"); | ||
365 | |||
366 | if self.replacements.is_empty() && self.insertions.is_empty() { | ||
367 | return node.clone(); | ||
368 | } | ||
369 | let green = self.rewrite_children(node); | ||
370 | with_green(node, green) | ||
371 | } | ||
372 | |||
373 | pub fn rewrite_ast<N: AstNode>(self, node: &N) -> N { | ||
374 | N::cast(self.rewrite(node.syntax())).unwrap() | ||
375 | } | ||
376 | |||
377 | /// Returns a node that encompasses all replacements to be done by this rewriter. | ||
378 | /// | ||
379 | /// Passing the returned node to `rewrite` will apply all replacements queued up in `self`. | ||
380 | /// | ||
381 | /// Returns `None` when there are no replacements. | ||
382 | pub fn rewrite_root(&self) -> Option<SyntaxNode> { | ||
383 | let _p = profile::span("rewrite_root"); | ||
384 | fn element_to_node_or_parent(element: &SyntaxElement) -> Option<SyntaxNode> { | ||
385 | match element { | ||
386 | SyntaxElement::Node(it) => Some(it.clone()), | ||
387 | SyntaxElement::Token(it) => it.parent(), | ||
388 | } | ||
389 | } | ||
390 | |||
391 | self.replacements | ||
392 | .keys() | ||
393 | .filter_map(element_to_node_or_parent) | ||
394 | .chain(self.insertions.keys().filter_map(|pos| match pos { | ||
395 | InsertPos::FirstChildOf(it) => Some(it.clone()), | ||
396 | InsertPos::After(it) => element_to_node_or_parent(it), | ||
397 | })) | ||
398 | // If we only have one replacement/insertion, we must return its parent node, since `rewrite` does | ||
399 | // not replace the node passed to it. | ||
400 | .map(|it| it.parent().unwrap_or(it)) | ||
401 | .fold1(|a, b| least_common_ancestor(&a, &b).unwrap()) | ||
402 | } | ||
403 | |||
404 | fn replacement(&self, element: &SyntaxElement) -> Option<Replacement> { | ||
405 | self.replacements.get(element).cloned() | ||
406 | } | ||
407 | |||
408 | fn insertions(&self, pos: &InsertPos) -> Option<impl Iterator<Item = SyntaxElement> + '_> { | ||
409 | self.insertions.get(pos).map(|insertions| insertions.iter().cloned()) | ||
410 | } | ||
411 | |||
412 | fn rewrite_children(&self, node: &SyntaxNode) -> rowan::GreenNode { | ||
413 | let _p = profile::span("rewrite_children"); | ||
414 | |||
415 | // FIXME: this could be made much faster. | ||
416 | let mut new_children = Vec::new(); | ||
417 | if let Some(elements) = self.insertions(&InsertPos::FirstChildOf(node.clone())) { | ||
418 | new_children.extend(elements.map(element_to_green)); | ||
419 | } | ||
420 | for child in node.children_with_tokens() { | ||
421 | self.rewrite_self(&mut new_children, &child); | ||
422 | } | ||
423 | |||
424 | rowan::GreenNode::new(rowan::SyntaxKind(node.kind() as u16), new_children) | ||
425 | } | ||
426 | |||
427 | fn rewrite_self( | ||
428 | &self, | ||
429 | acc: &mut Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, | ||
430 | element: &SyntaxElement, | ||
431 | ) { | ||
432 | let _p = profile::span("rewrite_self"); | ||
433 | |||
434 | if let Some(replacement) = self.replacement(&element) { | ||
435 | match replacement { | ||
436 | Replacement::Single(element) => acc.push(element_to_green(element)), | ||
437 | }; | ||
438 | } else { | ||
439 | match element { | ||
440 | NodeOrToken::Token(it) => acc.push(NodeOrToken::Token(it.green().to_owned())), | ||
441 | NodeOrToken::Node(it) => { | ||
442 | acc.push(NodeOrToken::Node(self.rewrite_children(it))); | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | if let Some(elements) = self.insertions(&InsertPos::After(element.clone())) { | ||
447 | acc.extend(elements.map(element_to_green)); | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | ||
453 | match element { | ||
454 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().into_owned()), | ||
455 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), | ||
456 | } | ||
457 | } | ||
458 | |||
459 | #[derive(Clone, Debug)] | ||
460 | enum Replacement { | ||
461 | Single(SyntaxElement), | ||
462 | } | ||
463 | |||
464 | fn with_children( | 333 | fn with_children( |
465 | parent: &SyntaxNode, | 334 | parent: &SyntaxNode, |
466 | new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, | 335 | new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>, |