|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""Every documented tier agrees with the target table. |
| 3 | +
|
| 4 | +WHY THIS EXISTS. `kKnownTargets` in modules/toolchain-model/src/triple.cppm is |
| 5 | +the single source for a row's tier, and four documents restate it: both |
| 6 | +READMEs, both copies of docs/21. When `wasm32-emscripten` became `verified` and |
| 7 | +the Android rows gained tiers, docs/21 was updated and the READMEs were not -- |
| 8 | +so the front page told a reader that three targets were `planned` while the |
| 9 | +engine had built and run two of them. Nothing compared the two, which is the |
| 10 | +whole reason it could drift. |
| 11 | +
|
| 12 | +THE DENOMINATOR IS THE ENGINE'S TABLE, not the documents'. A check that walked |
| 13 | +the documents would pass on a document that lists nothing; this one fails when |
| 14 | +a row the engine has is absent from a table that carries tiers at all, and when |
| 15 | +a tier disagrees. |
| 16 | +""" |
| 17 | +import re |
| 18 | +import sys |
| 19 | +from pathlib import Path |
| 20 | + |
| 21 | +ROOT = Path(__file__).resolve().parents[2] |
| 22 | +TABLE = ROOT / "modules/toolchain-model/src/triple.cppm" |
| 23 | +TIERS = ("verified", "preview", "planned") |
| 24 | + |
| 25 | +# The engine's answer. |
| 26 | +rows = {} |
| 27 | +for m in re.finditer(r'^\s*\{\s*"([a-z0-9_.+-]+)",\s*"(verified|preview|planned)"', |
| 28 | + TABLE.read_text(), re.M): |
| 29 | + rows[m.group(1)] = m.group(2) |
| 30 | +if len(rows) < 20: |
| 31 | + sys.exit(f"ERROR: only {len(rows)} rows parsed from {TABLE.name}; " |
| 32 | + "the pattern no longer matches the table") |
| 33 | + |
| 34 | +# Documents that carry a tier column at all. A document without one is not in |
| 35 | +# scope -- prose that mentions a target is not a claim about its tier. |
| 36 | +docs = [ |
| 37 | + ROOT / "README.md", |
| 38 | + ROOT / "README.zh-CN.md", |
| 39 | + ROOT / "docs/21-the-target-triple.md", |
| 40 | + ROOT / "docs/zh/21-the-target-triple.md", |
| 41 | +] |
| 42 | + |
| 43 | +fail = False |
| 44 | +for doc in docs: |
| 45 | + if not doc.exists(): |
| 46 | + print(f"ERROR: {doc.relative_to(ROOT)} is missing") |
| 47 | + fail = True |
| 48 | + continue |
| 49 | + seen = {} |
| 50 | + for line in doc.read_text().splitlines(): |
| 51 | + if not line.startswith("|"): |
| 52 | + continue |
| 53 | + cells = [c.strip() for c in line.strip().strip("|").split("|")] |
| 54 | + tier = next((c for c in cells if c in TIERS), None) |
| 55 | + if tier is None: |
| 56 | + continue |
| 57 | + # Every target named in the row's FIRST cell takes the row's tier. |
| 58 | + for name in re.findall(r"`([a-z0-9_.+-]+)`", cells[0]): |
| 59 | + if name in rows: |
| 60 | + seen[name] = tier |
| 61 | + if not seen: |
| 62 | + print(f"ERROR: {doc.relative_to(ROOT)} is listed here but names no " |
| 63 | + f"target with a tier; either it lost its table or this list is stale") |
| 64 | + fail = True |
| 65 | + continue |
| 66 | + for name, tier in sorted(seen.items()): |
| 67 | + if rows[name] != tier: |
| 68 | + print(f"ERROR: {doc.relative_to(ROOT)}: {name} documented as " |
| 69 | + f"'{tier}', the table says '{rows[name]}'") |
| 70 | + fail = True |
| 71 | + missing = sorted(set(rows) - set(seen)) |
| 72 | + if missing: |
| 73 | + print(f"ERROR: {doc.relative_to(ROOT)} carries tiers but omits " |
| 74 | + f"{len(missing)} row(s): {', '.join(missing)}") |
| 75 | + fail = True |
| 76 | + print(f" {doc.relative_to(ROOT)}: {len(seen)} of {len(rows)} rows") |
| 77 | + |
| 78 | +if fail: |
| 79 | + sys.exit(1) |
| 80 | +print(f"OK: {len(rows)} target tiers agree across {len(docs)} documents") |
0 commit comments