Store an ID on Syntax values and use it for vertex equality

pull/25/head
Wilfred Hughes 2021-07-13 20:54:23 +07:00
parent 8c1384368a
commit fbb2dffd4a
3 changed files with 49 additions and 3 deletions

@ -6,6 +6,8 @@ Improved parsing for Rust macro definitions and punctuation.
### Diffing
Diff calculation is now significantly faster.
Difftastic now considers nesting depth when comparing AST nodes, and
tries to match nodes with similar nesting levels.

@ -1,15 +1,30 @@
use std::cmp::{min, Ordering, Reverse};
use std::collections::BinaryHeap;
use std::hash::{Hash, Hasher};
use crate::syntax::{ChangeKind, Syntax};
use rustc_hash::{FxHashMap, FxHashSet};
use Edge::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone)]
struct Vertex<'a> {
lhs_syntax: Option<&'a Syntax<'a>>,
rhs_syntax: Option<&'a Syntax<'a>>,
}
impl<'a> PartialEq for Vertex<'a> {
fn eq(&self, other: &Self) -> bool {
self.lhs_syntax.map(|node| node.id()) == other.lhs_syntax.map(|node| node.id())
&& self.rhs_syntax.map(|node| node.id()) == other.rhs_syntax.map(|node| node.id())
}
}
impl<'a> Eq for Vertex<'a> {}
impl<'a> Hash for Vertex<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.lhs_syntax.map(|node| node.id()).hash(state);
self.rhs_syntax.map(|node| node.id()).hash(state);
}
}
impl<'a> Vertex<'a> {
fn is_end(&self) -> bool {
@ -342,6 +357,7 @@ mod tests {
let lhs = arena.alloc(Atom {
info: SyntaxInfo {
id: Cell::new(0),
pos_content_hash: 0,
next: Cell::new(None),
change: Cell::new(None),
@ -355,6 +371,7 @@ mod tests {
// Same content as LHS.
let rhs = arena.alloc(Atom {
info: SyntaxInfo {
id: Cell::new(1),
pos_content_hash: 1,
next: Cell::new(None),
change: Cell::new(None),

@ -42,6 +42,7 @@ pub struct SyntaxInfo<'a> {
pub next: Cell<Option<&'a Syntax<'a>>>,
pub change: Cell<Option<ChangeKind<'a>>>,
pub num_ancestors: Cell<u64>,
pub id: Cell<u64>,
}
pub enum Syntax<'a> {
@ -72,7 +73,7 @@ impl<'a> fmt::Debug for Syntax<'a> {
info,
..
} => {
let mut ds = f.debug_struct("List");
let mut ds = f.debug_struct(&format!("List:{}", self.id()));
ds.field("open_content", &open_content)
.field("children", &children)
@ -94,7 +95,7 @@ impl<'a> fmt::Debug for Syntax<'a> {
info,
..
} => {
let mut ds = f.debug_struct("Atom");
let mut ds = f.debug_struct(&format!("Atom:{}", self.id()));
ds.field("content", &content)
.field("change", &info.change.get());
ds.field("position", &position);
@ -144,6 +145,7 @@ impl<'a> Syntax<'a> {
arena.alloc(List {
info: SyntaxInfo {
id: Cell::new(0),
pos_content_hash: hasher.finish(),
next: Cell::new(None),
change: Cell::new(None),
@ -188,6 +190,7 @@ impl<'a> Syntax<'a> {
arena.alloc(Atom {
info: SyntaxInfo {
id: Cell::new(0),
pos_content_hash: hasher.finish(),
next: Cell::new(None),
change: Cell::new(None),
@ -210,6 +213,10 @@ impl<'a> Syntax<'a> {
self.info().next.get()
}
pub fn id(&self) -> u64 {
self.info().id.get()
}
pub fn set_change(&self, ck: ChangeKind<'a>) {
self.info().change.set(Some(ck));
}
@ -335,10 +342,28 @@ impl<'a> Syntax<'a> {
}
pub fn init_info<'a>(roots: &[&'a Syntax<'a>]) {
set_id(roots, 0);
set_next(roots, None);
set_num_ancestors(roots, 0);
}
fn set_id<'a>(nodes: &[&'a Syntax<'a>], prev_id: u64) -> u64 {
let mut id = prev_id + 1;
for node in nodes {
match node {
List { info, children, .. } => {
info.id.set(id);
id = set_id(children, id);
}
Atom { info, .. } => {
info.id.set(id);
}
}
id += 1;
}
id
}
fn set_next<'a>(nodes: &[&'a Syntax<'a>], parent_next: Option<&'a Syntax<'a>>) {
for (i, node) in nodes.iter().enumerate() {
let node_next = match nodes.get(i + 1) {
@ -832,6 +857,7 @@ mod tests {
assert_eq!(
Atom {
info: SyntaxInfo {
id: Cell::new(0),
pos_content_hash: 0,
next: Cell::new(None),
change: Cell::new(Some(Novel)),
@ -847,6 +873,7 @@ mod tests {
},
Atom {
info: SyntaxInfo {
id: Cell::new(1),
pos_content_hash: 1,
next: Cell::new(None),
change: Cell::new(None),