Skip to content

Commit d5ddd3b

Browse files
add a tip for possible method name mismatch
1 parent 5c096e7 commit d5ddd3b

1 file changed

Lines changed: 77 additions & 1 deletion

File tree

Code/ContextSystem/Contexter.cs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using SER.Code.Extensions;
66
using SER.Code.Helpers;
77
using SER.Code.Helpers.ResultSystem;
8+
using SER.Code.MethodSystem;
89
using SER.Code.ScriptSystem;
910
using SER.Code.TokenSystem.Structures;
1011
using SER.Code.TokenSystem.Tokens;
@@ -142,7 +143,9 @@ List<RunnableContext> contexts
142143

143144
if (firstToken is not IContextableToken contextable)
144145
{
145-
return rs + $"'{firstToken.RawRep}' is not a valid way to start a line. Perhaps you made a typo?";
146+
var text = $"'{firstToken.RawRep}' is not a valid way to start a line."
147+
+ (FindClosestMatch(firstToken.RawRep) is { } match ? $" Did you mean to use '{match}'?" : "");
148+
return rs + text.AsError();
146149
}
147150

148151
var context = contextable.GetContext(scr);
@@ -242,4 +245,77 @@ private static Result HandleCurrentContext(BaseToken token, RunnableContext cont
242245
endLineContexting = true;
243246
return true;
244247
}
248+
249+
private static List<string>? _suggestions = null;
250+
public static string? FindClosestMatch(string input)
251+
{
252+
if (_suggestions is null)
253+
{
254+
_suggestions = [];
255+
_suggestions.AddRange(MethodIndex.GetMethods().Select(m => m.Name));
256+
_suggestions.AddRange(KeywordToken.KeywordContexts.Select(k => k.KeywordName));
257+
}
258+
259+
var suggestion = _suggestions
260+
.Select(name => new { Name = name, Score = GetJaroWinklerSimilarity(input, name) })
261+
.Where(x => x.Score > 0.5)
262+
.OrderByDescending(x => x.Score)
263+
.FirstOrDefault();
264+
265+
return suggestion?.Name;
266+
}
267+
268+
public static double GetJaroWinklerSimilarity(string s1, string s2)
269+
{
270+
double jaroDist = GetJaroSimilarity(s1, s2);
271+
if (jaroDist < 0.7) return jaroDist;
272+
273+
int prefixLength = 0;
274+
for (int i = 0; i < Math.Min(4, Math.Min(s1.Length, s2.Length)); i++)
275+
{
276+
if (s1[i] == s2[i]) prefixLength++;
277+
else break;
278+
}
279+
280+
return jaroDist + prefixLength * 0.1 * (1.0 - jaroDist);
281+
}
282+
283+
private static double GetJaroSimilarity(string s1, string s2)
284+
{
285+
int s1Len = s1.Length, s2Len = s2.Length;
286+
if (s1Len == 0 && s2Len == 0) return 1.0;
287+
288+
int matchDistance = Math.Max(s1Len, s2Len) / 2 - 1;
289+
bool[] s1Matches = new bool[s1Len];
290+
bool[] s2Matches = new bool[s2Len];
291+
292+
int matches = 0;
293+
for (int i = 0; i < s1Len; i++)
294+
{
295+
int start = Math.Max(0, i - matchDistance);
296+
int end = Math.Min(i + matchDistance + 1, s2Len);
297+
for (int j = start; j < end; j++)
298+
{
299+
if (s2Matches[j] || s1[i] != s2[j]) continue;
300+
s1Matches[i] = true;
301+
s2Matches[j] = true;
302+
matches++;
303+
break;
304+
}
305+
}
306+
307+
if (matches == 0) return 0.0;
308+
309+
double transpositions = 0;
310+
int k = 0;
311+
for (int i = 0; i < s1Len; i++)
312+
{
313+
if (!s1Matches[i]) continue;
314+
while (!s2Matches[k]) k++;
315+
if (s1[i] != s2[k]) transpositions++;
316+
k++;
317+
}
318+
319+
return (matches / (double)s1Len + matches / (double)s2Len + (matches - transpositions / 2.0) / matches) / 3.0;
320+
}
245321
}

0 commit comments

Comments
 (0)