aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/algo.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src/algo.rs')
-rw-r--r--crates/syntax/src/algo.rs133
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
3use std::{fmt, hash::BuildHasherDefault, ops::RangeInclusive}; 3use std::{hash::BuildHasherDefault, ops::RangeInclusive};
4 4
5use indexmap::IndexMap; 5use indexmap::IndexMap;
6use itertools::Itertools; 6use 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)]
334enum InsertPos {
335 FirstChildOf(SyntaxNode),
336 After(SyntaxElement),
337}
338
339#[derive(Default)]
340pub 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
347impl 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
356impl 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
452fn 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)]
460enum Replacement {
461 Single(SyntaxElement),
462}
463
464fn with_children( 333fn 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>>,