Skip to content

Commit

Permalink
Finishes HiFiTreeDiff algorithm
Browse files Browse the repository at this point in the history
This finishes the complete algorithm for lists for the first time. The algorithm works in these steps:
* Trim equal elements from the head and the tail of both lists
* Detect common edits to lists with fast list patterns; this is an optional optimization
* Find the latest common sublist and split both lists in three parts: two different prefixes, two equal middle parts and two different post fixes. Recurse on the prefixes and the postfixes and concatenate their edits lists.
* Finally we end up with two empty lists or two lists without common elements; we collect the differences of each element position pairwise. Lists that became shorter get an additional edit to cut off the list, while lists that became shorter get one additional edit to add the new elements. The new elements inherit indentation from the pre-existing elements. 

For these changes additional tests still must be added later.
  • Loading branch information
jurgenvinju authored Jan 11, 2025
1 parent ed1ad03 commit cf798ec
Showing 1 changed file with 11 additions and 8 deletions.
19 changes: 11 additions & 8 deletions src/org/rascalmpl/library/analysis/diff/edits/HiFiTreeDiff.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -280,18 +280,21 @@ list[TextEdit] listDiff(loc span, int seps, list[Tree] originals, list[Tree] rep
+ listDiff(endCover(span, postO), seps, postO, postR)
;
}
else if (originals := replacements) {
else if (originals == [], replacements == []) {
return edits;
}
else if (size(originals) == size(replacements)) {
else {
// here we know there are no common elements anymore, only a common amount of different elements
common = min(size(originals), size(replacements));

return edits
+ [*treeDiff(a, b) | <a, b> <- zip2(originals, replacements)];
// first the minimal length pairwise replacements, essential for finding accidental commonalities
+ [*treeDiff(a, b) | <a, b> <- zip2(originals[..common], replacements[..common])];
// then we either remove the tail that became shorter:
+ [replace(cover(end(last), cover(originals[cover+1..])), "") | size(originals) > size(replacements), [*_, last] := originals[..common]]
// or we add new elements to the end, while inheriting indentation from the originals:
+ [replace(end(last), learnIndentation(span, yield(replacements[common+1..]), yield(originals))) | size(originals) < size(replacements)]
;
} else {
// TODO: make cases for shortering or lenghtening a list but
// mixing the common prefix with `treeDiff` to find more nested sharing
return edits
+ [replace(span, learnIndentation(span, yield(replacements), yield(originals)))];
}
}

Expand Down

0 comments on commit cf798ec

Please sign in to comment.