Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/org/rascalmpl/library/analysis/diff/edits/HiFiTreeDiff.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,94 @@ list[TextEdit] treeDiff(
= [replace(t@\loc, learnIndentation(t@\loc, "<r>", "<t>"))]
when t != r;

// Several ways of changing recursive expressions can be exploited to create very small diffs.
// This is comparable to finding large common sublists in the case of lists. If you look at
// unary and binary associative operators as a kind of operator-separated lists, this makes sense.

// remove a unary prefix operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [lit(_), _, sort(exp)], _), [Tree op, _, Tree r]),
r)
= [delete(fromUntil(op@\loc, r@\loc))];

// add a unary prefix operator
list[TextEdit] treeDiff(
Tree r,
appl(prod(sort(str exp), [lit(_), _, sort(exp)], _), [Tree op, Tree sp, r]))
= [replace(beginOf(r@\loc), "<op><sp>")];

// remove a unary postfix operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [sort(str exp), _, lit(_)], _), [Tree l, _, Tree r]),
r)
= [delete(cover([endOf(l@\loc), r@\loc]))];

// add a unary postfix operator
list[TextEdit] treeDiff(
Tree l,
appl(prod(sort(str exp), [sort(str exp), _, lit(_)], _), [l, Tree sp, Tree op]))
= [replace(endOf(l), "<sp><op>")];

// remove the left hand side of a binary operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [sort(exp), _, lit(_), _, sort(exp)], _), [Tree l, _, _, _, Tree r]),
r)
= [delete(fromUntil(l@\loc, r@\loc))];

// add the left hand side of a binary operator
list[TextEdit] treeDiff(
Tree r,
appl(prod(sort(str exp), [sort(exp), _, lit(_), _, sort(exp)], _), [Tree l, Tree sp1, Tree op, Tree sp2, r]))
= [replace(beginOf(r@\loc), "<l><sp1><op><sp2>")];

// remove the right hand side of a binary operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [sort(exp), _, lit(_), _, sort(exp)], _), [Tree l, _, _, _, Tree r]),
l)
= [delete(cover([endOf(l@\loc), r@\loc]))];

// add the right hand side of a binary operator
list[TextEdit] treeDiff(
Tree l,
appl(prod(sort(str exp), [sort(exp), _, lit(_), _, sort(exp)], _), [l, Tree sp1, Tree op, Tree sp2, Tree r]))
= [replace(endOf(l@\loc), "<sp1><op><sp2><r>")];

// change a binary operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [sort(exp), _, lit(str x), _, sort(exp)], _), [Tree l, _, Tree op, _, Tree r]),
appl(prod(sort(str exp), [sort(exp), _, lit(str y), _, sort(exp)], _), [l, _, Tree newOp, _, r]))
= [replace(op@\loc, "<newOp>")] when x != y;

// change a prefix operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [lit(str x), _, sort(exp)], _), [Tree op, _, Tree r]),
appl(prod(sort(str exp), [lit(str y), _, sort(exp)], _), [Tree newOp, _, r]))
= [replace(op@\loc, "<newOp>")] when x != y;

// change a postfix operator
list[TextEdit] treeDiff(
appl(prod(sort(str exp), [sort(exp), _, lit(str x)], _), [Tree l, _, Tree op]),
appl(prod(sort(str exp), [sort(exp), _, lit(str y)], _), [l, _, Tree newOp]))
= [replace(op@\loc, "<newOp>")] when x != y;

// remove brackets
list[TextEdit] treeDiff(
t:appl(prod(sort(str exp), [lit(_), _, sort(exp), _, lit(_)], {*_, \bracket()}), [_, _, Tree e, _, _]),
e)
= [
delete(fromUntil(beginOf(t@\loc), e@\loc)),
delete(fromUntil(endOf(e@\loc), endOf(t@\loc)))
];

// add brackets
list[TextEdit] treeDiff(
Tree e,
t:appl(prod(sort(str exp), [lit(_), _, sort(exp), _, lit(_)], {*_, \bracket()}), [Tree open, Tree sp1, Tree e, Tree sp2, Tree close]))
= [
replace(beginOf(e@\loc), "<open><sp1>"),
replace(endOf(e@\loc), "<sp2><close>")
];

// When the productions are different, we've found an edit, and there is no need to recurse deeper.
default list[TextEdit] treeDiff(
t:appl(Production p:prod(_,_,_), list[Tree] _),
Expand Down Expand Up @@ -383,6 +471,9 @@ up to `until`.
private loc fromUntil(loc from, loc until) = from.top(from.offset, until.offset - from.offset);
private int end(loc src) = src.offset + src.length;

private loc endOf(loc src) = src.top[offset=src.offset + src.length][length=0];
private loc beginOf(loc src) = src.top[offset=src.offset][length=0];

private loc after(loc src) = src(end(src), 0);

private loc endCover(loc span, []) = span(span.offset + span.length, 0);
Expand Down
Loading