sameNames
Two renderings of a line of code, alike but for some names (a definition written alone, and written with others,
where a name it had alone was taken): each name in a that's another in b, added to names.
export function sameNames(a: string, b: string, names: Map<string, string>) { const tokens = (s: string) => s.match(/[A-Za-z_$][\w$]*|\d[\w.]*|\s+|[^\s\w$]/g) ?? []; const x = tokens(a); const y = tokens(b); const ident = /^[A-Za-z_$]/; // the two aligned: a name where the other has another name, the rest the same (or only in one: `{ x: x_1 }`) const lcs = Array.from({ length: x.length + 1 }, () => Array.from({ length: y.length + 1 }, () => 0), ); for (let i = x.length - 1; i >= 0; i--) for (let j = y.length - 1; j >= 0; j--) lcs[i]![j] = x[i] === y[j] ? lcs[i + 1]![j + 1]! + 1 : Math.max(lcs[i + 1]![j]!, lcs[i]![j + 1]!); let i = 0; let j = 0; while (i < x.length && j < y.length) { if (x[i] === y[j]) { i++; j++; } else if (ident.test(x[i]!) && ident.test(y[j]!) && lcs[i + 1]![j + 1]! === lcs[i]![j]!) { if (!names.has(x[i]!)) names.set(x[i]!, y[j]!); i++; j++; } else if (lcs[i + 1]![j]! >= lcs[i]![j + 1]!) i++; else j++; } }