propagate annotations to mapped elements

This commit is contained in:
DropDemBits 2024-09-02 18:24:47 -04:00
parent db649195e9
commit 3440408087
No known key found for this signature in database
GPG key ID: 7FE02A6C1EDFA075
3 changed files with 168 additions and 52 deletions

View file

@ -22,19 +22,20 @@ impl SyntaxMapping {
Self::default()
}
/// Like [`SyntaxMapping::upmap_child`] but for syntax elements.
pub fn upmap_child_element(
&self,
child: &SyntaxElement,
input_ancestor: &SyntaxNode,
output_ancestor: SyntaxNode,
) -> SyntaxElement {
output_ancestor: &SyntaxNode,
) -> Result<SyntaxElement, MissingMapping> {
match child {
SyntaxElement::Node(node) => {
SyntaxElement::Node(self.upmap_child(node, input_ancestor, output_ancestor))
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);
self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor)?;
let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
debug_assert!(
@ -42,21 +43,26 @@ impl SyntaxMapping {
"token upmapping mapped to the wrong node ({token:?} -> {element:?})"
);
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,
) -> SyntaxNode {
debug_assert!(child.ancestors().any(|ancestor| &ancestor == input_ancestor));
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 =
let to_first_upmap = if child != input_ancestor {
std::iter::successors(Some((child.index(), child.clone())), |(_, current)| {
let parent = current.parent().unwrap();
@ -67,24 +73,14 @@ impl SyntaxMapping {
Some((parent.index(), parent))
})
.map(|(i, _)| i)
.collect::<Vec<_>>();
.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 {
std::iter::successors(Some((input_ancestor.index(), self.upmap_node(input_ancestor).unwrap_or_else(|| input_ancestor.clone()))), |(_, current)| {
let Some(parent) = current.parent() else {
unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}")
};
if &parent == &output_ancestor {
return None;
}
Some((parent.index(), match self.upmap_node(&parent) {
Some(next) => next,
None => parent
}))
}).map(|(i, _)| i).collect::<Vec<_>>()
let to_output_ancestor = if input_ancestor != output_ancestor {
self.upmap_to_ancestor(input_ancestor, output_ancestor)?
} else {
vec![]
};
@ -92,7 +88,7 @@ impl SyntaxMapping {
let to_map_down =
to_output_ancestor.into_iter().rev().chain(to_first_upmap.into_iter().rev());
let mut target = output_ancestor;
let mut target = output_ancestor.clone();
for index in to_map_down {
target = target
@ -104,20 +100,86 @@ impl SyntaxMapping {
debug_assert_eq!(child.kind(), target.kind());
target
Ok(target)
}
pub fn upmap_node(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
fn upmap_to_ancestor(
&self,
input_ancestor: &SyntaxNode,
output_ancestor: &SyntaxNode,
) -> Result<Vec<usize>, MissingMapping> {
eprintln!("mapping ancestor {input_ancestor:#?} to {output_ancestor:#?}");
let mut current =
self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone());
let mut upmap_chain = vec![current.index()];
let output = self.entry_parents[*parent as usize]
.children_with_tokens()
.nth(*child_slot as usize)
.and_then(SyntaxElement::into_node)
.unwrap();
loop {
let Some(parent) = current.parent() else { break };
debug_assert_eq!(input.kind(), output.kind());
Some(output)
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) {
@ -130,6 +192,20 @@ impl SyntaxMapping {
}));
}
/// 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)
}
fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) {
let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping;
@ -183,6 +259,9 @@ impl SyntaxMappingBuilder {
}
}
#[derive(Debug)]
pub struct MissingMapping(pub SyntaxNode);
#[derive(Debug, Clone, Copy)]
struct MappingEntry {
parent: u32,