@ -2,7 +2,9 @@
use bumpalo ::Bump ;
use bumpalo ::Bump ;
use rpds ::Stack ;
use rpds ::Stack ;
use rustc_hash ::FxHashMap ;
use std ::{
use std ::{
cell ::RefCell ,
cmp ::min ,
cmp ::min ,
fmt ,
fmt ,
hash ::{ Hash , Hasher } ,
hash ::{ Hash , Hasher } ,
@ -44,7 +46,9 @@ use Edge::*;
/// ^ ^
/// ^ ^
/// ```
/// ```
#[ derive(Debug, Clone) ]
#[ derive(Debug, Clone) ]
pub struct Vertex < ' a > {
pub struct Vertex < ' a , ' b > {
pub neighbours : RefCell < Option < Vec < ( Edge , & ' b Vertex < ' a , ' b > ) > > > ,
pub predecessor : RefCell < Option < ( u64 , & ' b Vertex < ' a , ' b > ) > > ,
pub lhs_syntax : Option < & ' a Syntax < ' a > > ,
pub lhs_syntax : Option < & ' a Syntax < ' a > > ,
pub rhs_syntax : Option < & ' a Syntax < ' a > > ,
pub rhs_syntax : Option < & ' a Syntax < ' a > > ,
parents : Stack < EnteredDelimiter < ' a > > ,
parents : Stack < EnteredDelimiter < ' a > > ,
@ -53,7 +57,7 @@ pub struct Vertex<'a> {
can_pop_either : bool ,
can_pop_either : bool ,
}
}
impl < ' a > PartialEq for Vertex < ' a > {
impl < ' a , ' b > PartialEq for Vertex < ' a , ' b > {
fn eq ( & self , other : & Self ) -> bool {
fn eq ( & self , other : & Self ) -> bool {
self . lhs_syntax . map ( | node | node . id ( ) ) = = other . lhs_syntax . map ( | node | node . id ( ) )
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 ( ) )
& & self . rhs_syntax . map ( | node | node . id ( ) ) = = other . rhs_syntax . map ( | node | node . id ( ) )
@ -83,9 +87,9 @@ impl<'a> PartialEq for Vertex<'a> {
& & self . can_pop_either = = other . can_pop_either
& & self . can_pop_either = = other . can_pop_either
}
}
}
}
impl < ' a > Eq for Vertex < ' a > { }
impl < ' a , ' b > Eq for Vertex < ' a , ' b > { }
impl < ' a > Hash for Vertex < ' a > {
impl < ' a , ' b > Hash for Vertex < ' a , ' b > {
fn hash < H : Hasher > ( & self , state : & mut H ) {
fn hash < H : Hasher > ( & self , state : & mut H ) {
self . lhs_syntax . map ( | node | node . id ( ) ) . hash ( state ) ;
self . lhs_syntax . map ( | node | node . id ( ) ) . hash ( state ) ;
self . rhs_syntax . map ( | node | node . id ( ) ) . hash ( state ) ;
self . rhs_syntax . map ( | node | node . id ( ) ) . hash ( state ) ;
@ -245,7 +249,7 @@ fn push_rhs_delimiter<'a>(
entered . push ( EnteredDelimiter ::PopEither ( ( lhs_delims , rhs_delims ) ) )
entered . push ( EnteredDelimiter ::PopEither ( ( lhs_delims , rhs_delims ) ) )
}
}
impl < ' a > Vertex < ' a > {
impl < ' a , ' b > Vertex < ' a , ' b > {
pub fn is_end ( & self ) -> bool {
pub fn is_end ( & self ) -> bool {
self . lhs_syntax . is_none ( ) & & self . rhs_syntax . is_none ( ) & & self . parents . is_empty ( )
self . lhs_syntax . is_none ( ) & & self . rhs_syntax . is_none ( ) & & self . parents . is_empty ( )
}
}
@ -253,6 +257,8 @@ impl<'a> Vertex<'a> {
pub fn new ( lhs_syntax : Option < & ' a Syntax < ' a > > , rhs_syntax : Option < & ' a Syntax < ' a > > ) -> Self {
pub fn new ( lhs_syntax : Option < & ' a Syntax < ' a > > , rhs_syntax : Option < & ' a Syntax < ' a > > ) -> Self {
let parents = Stack ::new ( ) ;
let parents = Stack ::new ( ) ;
Vertex {
Vertex {
neighbours : RefCell ::new ( None ) ,
predecessor : RefCell ::new ( None ) ,
lhs_syntax ,
lhs_syntax ,
rhs_syntax ,
rhs_syntax ,
parents ,
parents ,
@ -331,17 +337,34 @@ impl Edge {
}
}
}
}
/// Calculate all the neighbours from `v` and write them to `buf`.
fn allocate_if_new < ' syn , ' b > (
pub fn neighbours < ' a , ' b > (
v : Vertex < ' syn , ' b > ,
v : & Vertex < ' a > ,
buf : & mut [ Option < ( Edge , & ' b Vertex < ' a > ) > ] ,
alloc : & ' b Bump ,
alloc : & ' b Bump ,
) {
seen : & mut FxHashMap < & Vertex < ' syn , ' b > , & ' b Vertex < ' syn , ' b > > ,
for item in & mut * buf {
) -> & ' b Vertex < ' syn , ' b > {
* item = None ;
match seen . get ( & v ) {
Some ( existing ) = > * existing ,
None = > {
let allocated = alloc . alloc ( v ) ;
seen . insert ( allocated , allocated ) ;
allocated
}
}
}
}
let mut i = 0 ;
/// Compute the neighbours of `v` if we haven't previously done so,
/// write them to the .neighbours cell inside `v`, and return them.
pub fn get_set_neighbours < ' syn , ' b > (
v : & Vertex < ' syn , ' b > ,
alloc : & ' b Bump ,
seen : & mut FxHashMap < & Vertex < ' syn , ' b > , & ' b Vertex < ' syn , ' b > > ,
) -> Vec < ( Edge , & ' b Vertex < ' syn , ' b > ) > {
match & * v . neighbours . borrow ( ) {
Some ( neighbours ) = > return neighbours . clone ( ) ,
None = > { }
}
let mut res : Vec < ( Edge , & Vertex ) > = vec! [ ] ;
if v . lhs_syntax . is_none ( ) & & v . rhs_syntax . is_none ( ) {
if v . lhs_syntax . is_none ( ) & & v . rhs_syntax . is_none ( ) {
if let Some ( ( lhs_parent , rhs_parent , parents_next ) ) = try_pop_both ( & v . parents ) {
if let Some ( ( lhs_parent , rhs_parent , parents_next ) ) = try_pop_both ( & v . parents ) {
@ -349,18 +372,23 @@ pub fn neighbours<'a, 'b>(
// move up to the parent node.
// move up to the parent node.
// Continue from sibling of parent.
// Continue from sibling of parent.
buf[ i ] = Some ( (
res. push ( (
ExitDelimiterBoth ,
ExitDelimiterBoth ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_parent . next_sibling ( ) ,
Vertex {
rhs_syntax : rhs_parent . next_sibling ( ) ,
neighbours : RefCell ::new ( None ) ,
can_pop_either : can_pop_either_parent ( & parents_next ) ,
predecessor : RefCell ::new ( None ) ,
parents : parents_next ,
lhs_syntax : lhs_parent . next_sibling ( ) ,
lhs_parent_id : lhs_parent . parent ( ) . map ( Syntax ::id ) ,
rhs_syntax : rhs_parent . next_sibling ( ) ,
rhs_parent_id : rhs_parent . parent ( ) . map ( Syntax ::id ) ,
can_pop_either : can_pop_either_parent ( & parents_next ) ,
} ) ,
parents : parents_next ,
lhs_parent_id : lhs_parent . parent ( ) . map ( Syntax ::id ) ,
rhs_parent_id : rhs_parent . parent ( ) . map ( Syntax ::id ) ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
@ -369,18 +397,23 @@ pub fn neighbours<'a, 'b>(
// Move to next after LHS parent.
// Move to next after LHS parent.
// Continue from sibling of parent.
// Continue from sibling of parent.
buf[ i ] = Some ( (
res. push ( (
ExitDelimiterLHS ,
ExitDelimiterLHS ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_parent . next_sibling ( ) ,
Vertex {
rhs_syntax : v . rhs_syntax ,
neighbours : RefCell ::new ( None ) ,
can_pop_either : can_pop_either_parent ( & parents_next ) ,
predecessor : RefCell ::new ( None ) ,
parents : parents_next ,
lhs_syntax : lhs_parent . next_sibling ( ) ,
lhs_parent_id : lhs_parent . parent ( ) . map ( Syntax ::id ) ,
rhs_syntax : v . rhs_syntax ,
rhs_parent_id : v . rhs_parent_id ,
can_pop_either : can_pop_either_parent ( & parents_next ) ,
} ) ,
parents : parents_next ,
lhs_parent_id : lhs_parent . parent ( ) . map ( Syntax ::id ) ,
rhs_parent_id : v . rhs_parent_id ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
@ -389,18 +422,23 @@ pub fn neighbours<'a, 'b>(
// Move to next after RHS parent.
// Move to next after RHS parent.
// Continue from sibling of parent.
// Continue from sibling of parent.
buf[ i ] = Some ( (
res. push ( (
ExitDelimiterRHS ,
ExitDelimiterRHS ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : v . lhs_syntax ,
Vertex {
rhs_syntax : rhs_parent . next_sibling ( ) ,
neighbours : RefCell ::new ( None ) ,
can_pop_either : can_pop_either_parent ( & parents_next ) ,
predecessor : RefCell ::new ( None ) ,
parents : parents_next ,
lhs_syntax : v . lhs_syntax ,
lhs_parent_id : v . lhs_parent_id ,
rhs_syntax : rhs_parent . next_sibling ( ) ,
rhs_parent_id : rhs_parent . parent ( ) . map ( Syntax ::id ) ,
can_pop_either : can_pop_either_parent ( & parents_next ) ,
} ) ,
parents : parents_next ,
lhs_parent_id : v . lhs_parent_id ,
rhs_parent_id : rhs_parent . parent ( ) . map ( Syntax ::id ) ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
@ -411,18 +449,23 @@ pub fn neighbours<'a, 'b>(
. unsigned_abs ( ) ;
. unsigned_abs ( ) ;
// Both nodes are equal, the happy case.
// Both nodes are equal, the happy case.
buf[ i ] = Some ( (
res. push ( (
UnchangedNode { depth_difference } ,
UnchangedNode { depth_difference } ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_syntax . next_sibling ( ) ,
Vertex {
rhs_syntax : rhs_syntax . next_sibling ( ) ,
neighbours : RefCell ::new ( None ) ,
parents : v . parents . clone ( ) ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : v . lhs_parent_id ,
lhs_syntax : lhs_syntax . next_sibling ( ) ,
rhs_parent_id : v . rhs_parent_id ,
rhs_syntax : rhs_syntax . next_sibling ( ) ,
can_pop_either : v . can_pop_either ,
parents : v . parents . clone ( ) ,
} ) ,
lhs_parent_id : v . lhs_parent_id ,
rhs_parent_id : v . rhs_parent_id ,
can_pop_either : v . can_pop_either ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
if let (
if let (
@ -452,18 +495,23 @@ pub fn neighbours<'a, 'b>(
- rhs_syntax . num_ancestors ( ) as i32 )
- rhs_syntax . num_ancestors ( ) as i32 )
. unsigned_abs ( ) ;
. unsigned_abs ( ) ;
buf[ i ] = Some ( (
res. push ( (
EnterUnchangedDelimiter { depth_difference } ,
EnterUnchangedDelimiter { depth_difference } ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_next ,
Vertex {
rhs_syntax : rhs_next ,
neighbours : RefCell ::new ( None ) ,
parents : parents_next ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : Some ( lhs_syntax . id ( ) ) ,
lhs_syntax : lhs_next ,
rhs_parent_id : Some ( rhs_syntax . id ( ) ) ,
rhs_syntax : rhs_next ,
can_pop_either : false ,
parents : parents_next ,
} ) ,
lhs_parent_id : Some ( lhs_syntax . id ( ) ) ,
rhs_parent_id : Some ( rhs_syntax . id ( ) ) ,
can_pop_either : false ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
@ -485,18 +533,23 @@ pub fn neighbours<'a, 'b>(
if lhs_content ! = rhs_content {
if lhs_content ! = rhs_content {
let levenshtein_pct =
let levenshtein_pct =
( normalized_levenshtein ( lhs_content , rhs_content ) * 100.0 ) . round ( ) as u8 ;
( normalized_levenshtein ( lhs_content , rhs_content ) * 100.0 ) . round ( ) as u8 ;
buf[ i ] = Some ( (
res. push ( (
ReplacedComment { levenshtein_pct } ,
ReplacedComment { levenshtein_pct } ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_syntax . next_sibling ( ) ,
Vertex {
rhs_syntax : rhs_syntax . next_sibling ( ) ,
neighbours : RefCell ::new ( None ) ,
parents : v . parents . clone ( ) ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : v . lhs_parent_id ,
lhs_syntax : lhs_syntax . next_sibling ( ) ,
rhs_parent_id : v . rhs_parent_id ,
rhs_syntax : rhs_syntax . next_sibling ( ) ,
can_pop_either : v . can_pop_either ,
parents : v . parents . clone ( ) ,
} ) ,
lhs_parent_id : v . lhs_parent_id ,
rhs_parent_id : v . rhs_parent_id ,
can_pop_either : v . can_pop_either ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
}
}
@ -505,22 +558,27 @@ pub fn neighbours<'a, 'b>(
match lhs_syntax {
match lhs_syntax {
// Step over this novel atom.
// Step over this novel atom.
Syntax ::Atom { .. } = > {
Syntax ::Atom { .. } = > {
buf[ i ] = Some ( (
res. push ( (
NovelAtomLHS {
NovelAtomLHS {
// TODO: should this apply if prev is a parent
// TODO: should this apply if prev is a parent
// node rather than a sibling?
// node rather than a sibling?
contiguous : lhs_syntax . prev_is_contiguous ( ) ,
contiguous : lhs_syntax . prev_is_contiguous ( ) ,
} ,
} ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_syntax . next_sibling ( ) ,
Vertex {
rhs_syntax : v . rhs_syntax ,
neighbours : RefCell ::new ( None ) ,
parents : v . parents . clone ( ) ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : v . lhs_parent_id ,
lhs_syntax : lhs_syntax . next_sibling ( ) ,
rhs_parent_id : v . rhs_parent_id ,
rhs_syntax : v . rhs_syntax ,
can_pop_either : v . can_pop_either ,
parents : v . parents . clone ( ) ,
} ) ,
lhs_parent_id : v . lhs_parent_id ,
rhs_parent_id : v . rhs_parent_id ,
can_pop_either : v . can_pop_either ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
// Step into this partially/fully novel list.
// Step into this partially/fully novel list.
Syntax ::List { children , .. } = > {
Syntax ::List { children , .. } = > {
@ -528,20 +586,25 @@ pub fn neighbours<'a, 'b>(
let parents_next = push_lhs_delimiter ( & v . parents , lhs_syntax ) ;
let parents_next = push_lhs_delimiter ( & v . parents , lhs_syntax ) ;
buf[ i ] = Some ( (
res. push ( (
EnterNovelDelimiterLHS {
EnterNovelDelimiterLHS {
contiguous : lhs_syntax . prev_is_contiguous ( ) ,
contiguous : lhs_syntax . prev_is_contiguous ( ) ,
} ,
} ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : lhs_next ,
Vertex {
rhs_syntax : v . rhs_syntax ,
neighbours : RefCell ::new ( None ) ,
parents : parents_next ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : Some ( lhs_syntax . id ( ) ) ,
lhs_syntax : lhs_next ,
rhs_parent_id : v . rhs_parent_id ,
rhs_syntax : v . rhs_syntax ,
can_pop_either : true ,
parents : parents_next ,
} ) ,
lhs_parent_id : Some ( lhs_syntax . id ( ) ) ,
rhs_parent_id : v . rhs_parent_id ,
can_pop_either : true ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
}
}
@ -550,20 +613,25 @@ pub fn neighbours<'a, 'b>(
match rhs_syntax {
match rhs_syntax {
// Step over this novel atom.
// Step over this novel atom.
Syntax ::Atom { .. } = > {
Syntax ::Atom { .. } = > {
buf[ i ] = Some ( (
res. push ( (
NovelAtomRHS {
NovelAtomRHS {
contiguous : rhs_syntax . prev_is_contiguous ( ) ,
contiguous : rhs_syntax . prev_is_contiguous ( ) ,
} ,
} ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : v . lhs_syntax ,
Vertex {
rhs_syntax : rhs_syntax . next_sibling ( ) ,
neighbours : RefCell ::new ( None ) ,
parents : v . parents . clone ( ) ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : v . lhs_parent_id ,
lhs_syntax : v . lhs_syntax ,
rhs_parent_id : v . rhs_parent_id ,
rhs_syntax : rhs_syntax . next_sibling ( ) ,
can_pop_either : v . can_pop_either ,
parents : v . parents . clone ( ) ,
} ) ,
lhs_parent_id : v . lhs_parent_id ,
rhs_parent_id : v . rhs_parent_id ,
can_pop_either : v . can_pop_either ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
// Step into this partially/fully novel list.
// Step into this partially/fully novel list.
Syntax ::List { children , .. } = > {
Syntax ::List { children , .. } = > {
@ -571,30 +639,41 @@ pub fn neighbours<'a, 'b>(
let parents_next = push_rhs_delimiter ( & v . parents , rhs_syntax ) ;
let parents_next = push_rhs_delimiter ( & v . parents , rhs_syntax ) ;
buf[ i ] = Some ( (
res. push ( (
EnterNovelDelimiterRHS {
EnterNovelDelimiterRHS {
contiguous : rhs_syntax . prev_is_contiguous ( ) ,
contiguous : rhs_syntax . prev_is_contiguous ( ) ,
} ,
} ,
alloc . alloc ( Vertex {
allocate_if_new (
lhs_syntax : v . lhs_syntax ,
Vertex {
rhs_syntax : rhs_next ,
neighbours : RefCell ::new ( None ) ,
parents : parents_next ,
predecessor : RefCell ::new ( None ) ,
lhs_parent_id : v . lhs_parent_id ,
lhs_syntax : v . lhs_syntax ,
rhs_parent_id : Some ( rhs_syntax . id ( ) ) ,
rhs_syntax : rhs_next ,
can_pop_either : true ,
parents : parents_next ,
} ) ,
lhs_parent_id : v . lhs_parent_id ,
rhs_parent_id : Some ( rhs_syntax . id ( ) ) ,
can_pop_either : true ,
} ,
alloc ,
seen ,
) ,
) ) ;
) ) ;
i + = 1 ;
}
}
}
}
}
}
assert! (
assert! (
i > 0 ,
res. len ( ) > 0 ,
" Must always find some next steps if node is not the end "
" Must always find some next steps if node is not the end "
) ;
) ;
v . neighbours . replace ( Some ( res . clone ( ) ) ) ;
res
}
}
pub fn populate_change_map < ' a > ( route : & [ ( Edge , Vertex < ' a > ) ] , change_map : & mut ChangeMap < ' a > ) {
pub fn populate_change_map < ' a , ' b > (
route : & [ ( Edge , & ' b Vertex < ' a , ' b > ) ] ,
change_map : & mut ChangeMap < ' a > ,
) {
for ( e , v ) in route {
for ( e , v ) in route {
match e {
match e {
ExitDelimiterBoth | ExitDelimiterLHS | ExitDelimiterRHS = > {
ExitDelimiterBoth | ExitDelimiterLHS | ExitDelimiterRHS = > {