diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index e5bfe24..fe35ba4 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -3,21 +3,22 @@ module analysis::typepal::Solver /* Implementation of the ISolver interface; this is the API of TypePal's constraint solver */ -import Set; -import Node; -import Map; +extend analysis::typepal::Collector; +extend analysis::typepal::Messenger; + +import Exception; import IO; import List; import Location; +import Map; +import Message; +import Node; import ParseTree; -import Type; +import Set; import String; -import Message; -import Exception; -//import util::Benchmark; - -extend analysis::typepal::Collector; -extend analysis::typepal::Messenger; +import Type; +import analysis::typepal::StringSimilarity; +import util::IDEServices; void checkAllTypesAvailable(TModel tm){ for(tup: <- tm.defines){ @@ -1517,13 +1518,13 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ foundDefs = scopeGraph.lookup(u); } catch NoBinding(): { roles = size(u.idRoles) > 5 ? "" : intercalateOr([prettyRole(idRole) | idRole <- u.idRoles]); - messages += error("Undefined ``", u.occ); + messages += error("Undefined ``", u.occ, fixes=undefinedNameProposals(u, tm)); } } for(u <- notYetDefinedUses){ roles = size(u.idRoles) > 5 ? "" : intercalateOr([prettyRole(idRole) | idRole <- u.idRoles]); - messages += error("Undefined ``", u.occ); + messages += error("Undefined ``", u.occ, fixes=undefinedNameProposals(u, tm)); } error_locations = { src | error(_,loc src) <- messages }; @@ -1704,3 +1705,14 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ return thisSolver; } + +// CodeActions for errors generated by Solver + +list[CodeAction] undefinedNameProposals(Use u, TModel tm) + = + [ action( + title="Replace undefined ``", + edits=[changed([replace(u.occ, prop)])] + ) + | str prop <- similarNames(getOrgId(u), u.idRoles, tm, 3) + ]; \ No newline at end of file diff --git a/src/analysis/typepal/StringSimilarity.rsc b/src/analysis/typepal/StringSimilarity.rsc index 12de519..afd3866 100644 --- a/src/analysis/typepal/StringSimilarity.rsc +++ b/src/analysis/typepal/StringSimilarity.rsc @@ -1,41 +1,37 @@ module analysis::typepal::StringSimilarity -import String; import List; +import String; +import analysis::typepal::TModel; +@synopsis{Tryadic minimum function on integers} int min(int a, int b, int c) = a < b ? (a < c ? a : c) : (b < c ? b : c); @synopsis{Calculate the Levenshtein distance of 2 strings} -@memo -int lev(str a, str b) - = lev(a, 0, b, 0); - -@memo -private int lev(str a, int ia, str b, int ib){ - if(ib == size(b)) return size(a) - ia; - if(ia == size(a)) return size(b) - ib; - if(a[ia] == b[ib]) return lev(a, ia+1, b, ib+1); - - return 1 + min(lev(a, ia+1, b, ib), - lev(a, ia, b, ib+1), - lev(a, ia+1, b, ib+1)); +int lev(str a, str b){ + int sizea = size(a); + int sizeb = size(b); + + @memo + int lev(int ia, int ib){ + if(ib == sizeb) return sizea - ia; + if(ia == sizea) return sizeb - ib; + if(a[ia] == b[ib]) return lev(ia+1, ib+1); + + return 1 + min(lev(ia+1, ib), + lev(ia, ib+1), + lev(ia+1, ib+1)); + } + + return lev(0, 0); } -// @memo -// private int lev(str a, int ia, int lena, str b, int ib, int lenb){ -// if(lenb == 0) return lena; -// if(lena == 0) return lenb; -// if(a[ia] == b[ib]) return lev(a, ia+1, lena-1, b, ib+1, lenb-1); +// Tests for `lev` -// return 1 + min(lev(a, ia+1, lena-1, b, ib, lenb), -// lev(a, ia, lena, b, ib+1, lenb-1), -// lev(a, ia+1, lena-1, b, ib+1, lenb-1)); -// } +test bool levCommutative(str a, str b) = lev(a, b) == lev(b, a); -test bool lev0(str a, str b) = lev(a, b) == lev(b, a); - -test bool levx(str a, str b, str c) = lev(a, b) == lev(c + a, c + b); +test bool levLeftAdditive(str a, str b, str c) = lev(a, b) == lev(c + a, c + b); test bool lev1() = lev("kitten", "sitting") == 3; test bool lev2() = lev("kelm", "hello") == 3; @@ -47,10 +43,17 @@ test bool lev7() = lev("page", "pope") == 2; test bool lev8() = lev("december", "january") == 8; test bool lev9() = lev("march", "may") == 3; +// Similarity functions to be used by TypePal +@synopsis{WordSim represents one word from the vocabulary and its similariy to the original word} alias WordSim = tuple[str word, int sim]; +@synopsis{Compute list of words from vocabulary, that are similar to give word w with at most maxDistance edits} list[str] similarWords(str w, list[str] vocabulary, int maxDistance) = sort([ | str v <- vocabulary, d := lev(w, v), d <= maxDistance ], bool (WordSim x, WordSim y){ return x.sim < y.sim;}).word; -value main() = similarWords("ac", ["a", "ab", "ac", "x"], 10); \ No newline at end of file +@synopsis{Find in TModel tm, names similar to w, in gives roles, with at most maxDistance edits} +list[str] similarNames(str w, set[IdRole] idRoles, TModel tm, int maxDistance){ + vocabulary = [ d.orgId | d <- tm.defines, d.idRole in idRoles ]; + return similarWords(w, vocabulary, maxDistance); +}