use std::sync::Arc;
use crate::tree::green::{GreenElement, GreenNode};
use crate::tree::red::SyntaxNode;
use crate::tree::transform::Transformer;
use crate::types::Span;
pub use crate::diagnostics::source_map::{SpanMap, SpanMapping, map_offset};
pub fn transform_with_mapping(
root: &SyntaxNode,
transformer: &mut impl Transformer,
) -> (SyntaxNode, SpanMap) {
let mut map = SpanMap::new();
let new_green = rebuild_with_map(root, transformer, 0, &mut map);
map.sort();
(SyntaxNode::new_root(new_green), map)
}
fn rebuild_with_map(
node: &SyntaxNode,
transformer: &mut impl Transformer,
new_offset: u32,
map: &mut SpanMap,
) -> Arc<GreenNode> {
if let Some(replacement) = transformer.transform_node(node) {
return replacement;
}
let old_span = node.text_range();
let green = node.green();
let mut new_children = Vec::with_capacity(green.children.len());
let mut old_off = node.offset();
let mut new_off = new_offset;
for child in &green.children {
match child {
GreenElement::Node(child_green) => {
let child_red = SyntaxNode::new(Arc::clone(child_green), old_off);
let child_new = rebuild_with_map(&child_red, transformer, new_off, map);
let len = child_new.text_len;
new_children.push(GreenElement::Node(child_new));
old_off += child_green.text_len;
new_off += len;
}
GreenElement::Token(t) => {
new_children.push(GreenElement::Token(Arc::clone(t)));
let len = t.text_len;
old_off += len;
new_off += len;
}
}
}
let new_span = Span::new(new_offset, new_off);
map.push(new_span, old_span);
GreenNode::new(node.kind(), new_children)
}