mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-15 14:55:04 +00:00
270 lines
8.8 KiB
Rust
270 lines
8.8 KiB
Rust
//! Maps syntax elements through disjoint syntax nodes.
|
|
//!
|
|
//! [`SyntaxMappingBuilder`] should be used to create mappings to add to a [`SyntaxEditor`]
|
|
|
|
use itertools::Itertools;
|
|
use rustc_hash::FxHashMap;
|
|
|
|
use crate::{SyntaxElement, SyntaxNode};
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct SyntaxMapping {
|
|
// important information to keep track of:
|
|
// node -> node
|
|
// token -> token (implicit in mappings)
|
|
// input parent -> output parent (for deep lookups)
|
|
|
|
// mappings -> parents
|
|
entry_parents: Vec<SyntaxNode>,
|
|
node_mappings: FxHashMap<SyntaxNode, MappingEntry>,
|
|
}
|
|
|
|
impl SyntaxMapping {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
/// Like [`SyntaxMapping::upmap_child`] but for syntax elements.
|
|
pub fn upmap_child_element(
|
|
&self,
|
|
child: &SyntaxElement,
|
|
input_ancestor: &SyntaxNode,
|
|
output_ancestor: &SyntaxNode,
|
|
) -> Result<SyntaxElement, MissingMapping> {
|
|
match child {
|
|
SyntaxElement::Node(node) => {
|
|
self.upmap_child(node, input_ancestor, output_ancestor).map(SyntaxElement::Node)
|
|
}
|
|
SyntaxElement::Token(token) => {
|
|
let upmap_parent =
|
|
self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor)?;
|
|
|
|
let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
|
|
debug_assert!(
|
|
element.as_token().is_some_and(|it| it.kind() == token.kind()),
|
|
"token upmapping mapped to the wrong node ({token:?} -> {element:?})"
|
|
);
|
|
|
|
Ok(element)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Maps a child node of the input ancestor to the corresponding node in
|
|
/// the output ancestor.
|
|
pub fn upmap_child(
|
|
&self,
|
|
child: &SyntaxNode,
|
|
input_ancestor: &SyntaxNode,
|
|
output_ancestor: &SyntaxNode,
|
|
) -> Result<SyntaxNode, MissingMapping> {
|
|
debug_assert!(
|
|
child == input_ancestor
|
|
|| child.ancestors().any(|ancestor| &ancestor == input_ancestor)
|
|
);
|
|
|
|
// Build a list mapping up to the first mappable ancestor
|
|
let to_first_upmap = if child != input_ancestor {
|
|
std::iter::successors(Some((child.index(), child.clone())), |(_, current)| {
|
|
let parent = current.parent().unwrap();
|
|
|
|
if &parent == input_ancestor {
|
|
return None;
|
|
}
|
|
|
|
Some((parent.index(), parent))
|
|
})
|
|
.map(|(i, _)| i)
|
|
.collect::<Vec<_>>()
|
|
} else {
|
|
vec![]
|
|
};
|
|
|
|
// Progressively up-map the input ancestor until we get to the output ancestor
|
|
let to_output_ancestor = if input_ancestor != output_ancestor {
|
|
self.upmap_to_ancestor(input_ancestor, output_ancestor)?
|
|
} else {
|
|
vec![]
|
|
};
|
|
|
|
let to_map_down =
|
|
to_output_ancestor.into_iter().rev().chain(to_first_upmap.into_iter().rev());
|
|
|
|
let mut target = output_ancestor.clone();
|
|
|
|
for index in to_map_down {
|
|
target = target
|
|
.children_with_tokens()
|
|
.nth(index)
|
|
.and_then(|it| it.into_node())
|
|
.expect("equivalent ancestor node should be present in target tree");
|
|
}
|
|
|
|
debug_assert_eq!(child.kind(), target.kind());
|
|
|
|
Ok(target)
|
|
}
|
|
|
|
fn upmap_to_ancestor(
|
|
&self,
|
|
input_ancestor: &SyntaxNode,
|
|
output_ancestor: &SyntaxNode,
|
|
) -> Result<Vec<usize>, MissingMapping> {
|
|
let mut current =
|
|
self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone());
|
|
let mut upmap_chain = vec![current.index()];
|
|
|
|
loop {
|
|
let Some(parent) = current.parent() else { break };
|
|
|
|
if &parent == output_ancestor {
|
|
return Ok(upmap_chain);
|
|
}
|
|
|
|
current = match self.upmap_node_single(&parent) {
|
|
Some(next) => next,
|
|
None => parent,
|
|
};
|
|
upmap_chain.push(current.index());
|
|
}
|
|
|
|
Err(MissingMapping(current))
|
|
}
|
|
|
|
pub fn upmap_element(
|
|
&self,
|
|
input: &SyntaxElement,
|
|
output_root: &SyntaxNode,
|
|
) -> Option<Result<SyntaxElement, MissingMapping>> {
|
|
match input {
|
|
SyntaxElement::Node(node) => {
|
|
Some(self.upmap_node(node, output_root)?.map(SyntaxElement::Node))
|
|
}
|
|
SyntaxElement::Token(token) => {
|
|
let upmap_parent = match self.upmap_node(&token.parent().unwrap(), output_root)? {
|
|
Ok(it) => it,
|
|
Err(err) => return Some(Err(err)),
|
|
};
|
|
|
|
let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
|
|
debug_assert!(
|
|
element.as_token().is_some_and(|it| it.kind() == token.kind()),
|
|
"token upmapping mapped to the wrong node ({token:?} -> {element:?})"
|
|
);
|
|
|
|
Some(Ok(element))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn upmap_node(
|
|
&self,
|
|
input: &SyntaxNode,
|
|
output_root: &SyntaxNode,
|
|
) -> Option<Result<SyntaxNode, MissingMapping>> {
|
|
// Try to follow the mapping tree, if it exists
|
|
let input_mapping = self.upmap_node_single(input);
|
|
let input_ancestor =
|
|
input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor));
|
|
|
|
match (input_mapping, input_ancestor) {
|
|
(Some(input_mapping), _) => {
|
|
// A mapping exists at the input, follow along the tree
|
|
Some(self.upmap_child(&input_mapping, &input_mapping, output_root))
|
|
}
|
|
(None, Some(input_ancestor)) => {
|
|
// A mapping exists at an ancestor, follow along the tree
|
|
Some(self.upmap_child(input, &input_ancestor, output_root))
|
|
}
|
|
(None, None) => {
|
|
// No mapping exists at all, is the same position in the final tree
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn merge(&mut self, mut other: SyntaxMapping) {
|
|
// Remap other's entry parents to be after the current list of entry parents
|
|
let remap_base: u32 = self.entry_parents.len().try_into().unwrap();
|
|
|
|
self.entry_parents.append(&mut other.entry_parents);
|
|
self.node_mappings.extend(other.node_mappings.into_iter().map(|(node, entry)| {
|
|
(node, MappingEntry { parent: entry.parent + remap_base, ..entry })
|
|
}));
|
|
}
|
|
|
|
/// Follows the input one step along the syntax mapping tree
|
|
fn upmap_node_single(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
|
|
let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
|
|
|
|
let output = self.entry_parents[*parent as usize]
|
|
.children_with_tokens()
|
|
.nth(*child_slot as usize)
|
|
.and_then(SyntaxElement::into_node)
|
|
.unwrap();
|
|
|
|
debug_assert_eq!(input.kind(), output.kind());
|
|
Some(output)
|
|
}
|
|
|
|
pub fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) {
|
|
let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping;
|
|
|
|
let parent_entry: u32 = self.entry_parents.len().try_into().unwrap();
|
|
self.entry_parents.push(parent_node);
|
|
|
|
let node_entries = node_mappings
|
|
.into_iter()
|
|
.map(|(node, slot)| (node, MappingEntry { parent: parent_entry, child_slot: slot }));
|
|
|
|
self.node_mappings.extend(node_entries);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct SyntaxMappingBuilder {
|
|
parent_node: SyntaxNode,
|
|
node_mappings: Vec<(SyntaxNode, u32)>,
|
|
}
|
|
|
|
impl SyntaxMappingBuilder {
|
|
pub fn new(parent_node: SyntaxNode) -> Self {
|
|
Self { parent_node, node_mappings: vec![] }
|
|
}
|
|
|
|
pub fn map_node(&mut self, input: SyntaxNode, output: SyntaxNode) {
|
|
debug_assert_eq!(output.parent().as_ref(), Some(&self.parent_node));
|
|
self.node_mappings.push((input, output.index() as u32));
|
|
}
|
|
|
|
pub fn map_children(
|
|
&mut self,
|
|
input: impl Iterator<Item = SyntaxNode>,
|
|
output: impl Iterator<Item = SyntaxNode>,
|
|
) {
|
|
for pairs in input.zip_longest(output) {
|
|
let (input, output) = match pairs {
|
|
itertools::EitherOrBoth::Both(l, r) => (l, r),
|
|
itertools::EitherOrBoth::Left(_) => {
|
|
unreachable!("mapping more input nodes than there are output nodes")
|
|
}
|
|
itertools::EitherOrBoth::Right(_) => break,
|
|
};
|
|
|
|
self.map_node(input, output);
|
|
}
|
|
}
|
|
|
|
pub fn finish(self, mappings: &mut SyntaxMapping) {
|
|
mappings.add_mapping(self);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MissingMapping(pub SyntaxNode);
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
struct MappingEntry {
|
|
parent: u32,
|
|
child_slot: u32,
|
|
}
|