Download code/bugfind/bench/difffuncs.py from viai957/align: direct link, hf CLI and curl.
- Browser
- Download file 2.25 kB
-
https://huggingface.co/viai957/align/resolve/main/code/bugfind/bench/difffuncs.py
- Command line
-
hf download hf://viai957/align/code/bugfind/bench/difffuncs.py
-
curl -L -o difffuncs.py https://huggingface.co/viai957/align/resolve/main/code/bugfind/bench/difffuncs.py
2.25 kB
| """Find the functions whose bodies changed between two unpacked crate versions (pre-side names), by line-range | |
| overlap of difflib opcodes with a regex-located enclosing `fn`. Heuristic (no parser), documented as such.""" | |
| import difflib, os, re | |
| FN = re.compile(r"^\s*(?:pub(?:\([^)]*\))?\s+)?(?:const\s+)?(?:unsafe\s+)?(?:async\s+)?(?:extern\s+\"[^\"]*\"\s+)?fn\s+([A-Za-z_]\w*)") | |
| def modpath(rel): | |
| p = rel[len("src/"):-3].split("/") | |
| if p[-1] in ("mod", "lib"): p = p[:-1] | |
| return p | |
| def changed_functions(pre, post): | |
| out = [] | |
| for dp, _, fs in os.walk(os.path.join(pre, "src")): | |
| for f in fs: | |
| if not f.endswith(".rs"): continue | |
| rel = os.path.relpath(os.path.join(dp, f), pre) | |
| if rel.endswith("main.rs") and rel == "src/main.rs": continue | |
| a = open(os.path.join(pre, rel), encoding="utf8", errors="replace").read().splitlines() | |
| pp = os.path.join(post, rel) | |
| b = open(pp, encoding="utf8", errors="replace").read().splitlines() if os.path.exists(pp) else [] | |
| if a == b: continue | |
| # skip test code: everything from a `#[cfg(test)]` line on, and fns directly under `#[test]` | |
| cut = next((i for i, l in enumerate(a) if re.match(r"\s*#\[cfg\(test\)\]", l)), len(a)) | |
| starts = [(i, FN.match(l).group(1)) for i, l in enumerate(a[:cut]) if FN.match(l) and not any("#[test]" in a[k] for k in range(max(0, i - 3), i))] | |
| if cut < len(a): | |
| a, b = a[:cut], b[: next((i for i, l in enumerate(b) if re.match(r"\s*#\[cfg\(test\)\]", l)), len(b))] | |
| for tag, i1, i2, j1, j2 in difflib.SequenceMatcher(None, a, b, autojunk=False).get_opcodes(): | |
| if tag == "equal": continue | |
| for ln in sorted({i1, max(i2 - 1, i1)}): | |
| cands = [s for s in starts if s[0] <= ln] | |
| if cands: | |
| name = cands[-1][1] | |
| # a `fn` header preceding the changed line only counts if the change is within a plausible body (<= 400 lines) | |
| if ln - cands[-1][0] <= 400: | |
| out.append((rel, ".".join(modpath(rel)).replace(".", "::"), name)) | |
| return sorted(set(out)) | |