Something went wrong. Try again.
AppleScript grammar for tree-sitter
applescript tree-sitter-grammar tree-sitter
Something went wrong. Try again.
4.4 kB · 123 lines
Python
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124#!/usr/bin/env python3"""Report real-world parse health as the share of bytes inside ERROR nodes.
A file either having or not having an ERROR node is too blunt to steer by: aone-token slip and a file the parser could not enter at all both score zero.Byte coverage separates them, and it tracks what a user actually sees in aneditor, since an ERROR node is the span that loses its highlighting.
Usage: scripts/parse-health.py [dir-or-file ...]
Defaults to additional_examples/ and errors/, which are local scratch and notpart of the published grammar. Run it before and after any grammar change."""
import osimport reimport statisticsimport subprocessimport sys
# Nested ERROR nodes are common, so spans are unioned rather than summed.ERROR_SPAN = re.compile(r"\(ERROR \[(\d+), (\d+)\] - \[(\d+), (\d+)\]")MISSING = re.compile(r"\(MISSING\b")
DEFAULT_PATHS = ["additional_examples", "errors"]
def line_offsets(text): """Byte offset of the start of each line, plus one past the end.""" offsets = [0] for line in text.split("\n"): offsets.append(offsets[-1] + len(line.encode()) + 1) return offsets
def measure(path): """Return (size, error_bytes, missing_count), or None if the parse failed.""" source = open(path, encoding="utf-8", errors="replace").read() size = len(source.encode()) if size == 0: return None
result = subprocess.run( ["tree-sitter", "parse", path], capture_output=True, text=True ) tree = result.stdout if not tree: return None
offsets = line_offsets(source) covered = set() for row1, col1, row2, col2 in ERROR_SPAN.findall(tree): start = offsets[int(row1)] + int(col1) end = min(offsets[int(row2)] + int(col2), offsets[-1]) covered.update(range(start, end))
return size, len(covered), len(MISSING.findall(tree))
def collect(paths): for path in paths: if os.path.isfile(path): yield path for root, _, names in os.walk(path): for name in sorted(names): if name.endswith(".applescript"): yield os.path.join(root, name)
def main(): paths = sys.argv[1:] or [p for p in DEFAULT_PATHS if os.path.isdir(p)] if not paths: sys.exit(f"no corpus found; looked for {', '.join(DEFAULT_PATHS)}")
# The same script appears in both default directories, so measure each # basename once. seen, rows = set(), [] for path in collect(paths): name = os.path.basename(path) if name in seen: continue seen.add(name) result = measure(path) if result is None: continue size, error_bytes, missing = result rows.append((100 * error_bytes / size, path, size, missing))
if not rows: sys.exit("no files measured")
total = sum(size for _, _, size, _ in rows) total_error = sum(pct * size / 100 for pct, _, size, _ in rows) bad = sorted((r for r in rows if r[0] > 0), reverse=True)
print(f"files {len(rows)}") print(f"clean {len(rows) - len(bad)}") print(f"error bytes {100 * total_error / total:.1f}% of {total} bytes") if bad: median = statistics.median(pct for pct, _, _, _ in bad) print(f"median, files w/err {median:.1f}%") print(f"under 5% of file {sum(1 for pct, _, _, _ in bad if pct < 5)}/{len(bad)}")
# Total-loss files dominate the byte share and hide how the rest are # doing, so report the split. A file above 25% has usually lost a whole # block to one unsupported construct rather than degraded gradually. lost = [r for r in bad if r[0] > 25] if lost: lost_bytes = sum(pct * size / 100 for pct, _, size, _ in lost) rest = total_error - lost_bytes print( f"of which {len(lost)} total losses " f"{100 * lost_bytes / total_error:.0f}% of all ERROR bytes" ) print(f"the other {len(rows) - len(lost):<10d} {100 * rest / total:.1f}% of bytes") print("\nworst:") for pct, path, _, missing in bad[:10]: note = f" ({missing} MISSING)" if missing else "" print(f" {pct:5.1f}% {os.path.basename(path)}{note}")
if __name__ == "__main__": main()