#!/usr/bin/env python3 # checks docs/LEARN.md against the examples it shows. every examples/learn/*.zc runs # from the repo root with its stdout compared to the matching .out file, and # every ```zc block in docs/LEARN.md must be exactly one of those files, so the # guide can't drift from the code it teaches. usage: learn.py path/to/zy import glob, os, platform, re, subprocess, sys root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) os.chdir(root) zy = os.path.abspath(sys.argv[1]) x86_only = {"22-raw-x86"} bad = 0 def ok(name): print(f"ok {name}") def fail(name, why): global bad bad += 1 print(f"FAIL {name}: {why}") files = sorted(glob.glob("examples/learn/*.zc")) for path in files: name = os.path.splitext(os.path.basename(path))[0] if name in x86_only and platform.machine() not in ("x86_64", "AMD64"): print(f"skip {name} (x86-64 only)") continue with open(path, "rb") as f: src = f.read() try: r = subprocess.run([zy], stdin=open(path, "rb"), capture_output=True, timeout=30) except subprocess.TimeoutExpired: fail(f"learn {name}", "timed out") continue got = r.stdout.decode("utf-8", "replace") want_path = os.path.splitext(path)[0] + ".out" if not os.path.exists(want_path): fail(f"learn {name}", f"no {want_path}") elif got == open(want_path, encoding="utf-8").read(): ok(f"learn {name} prints what it says") else: fail(f"learn {name}", f"got [{got}]") # every zc block in docs/LEARN.md is one of the example files with open("docs/LEARN.md", encoding="utf-8") as f: doc = f.read() blocks = re.findall(r"^```zc\n(.*?)^```", doc, re.S | re.M) srcs = {} for path in files: with open(path, encoding="utf-8") as f: srcs[os.path.basename(path)] = f.read() used = set() for b in blocks: hit = [n for n, s in srcs.items() if s == b] if hit: used.add(hit[0]) else: fail("learn block", "a ```zc block in docs/LEARN.md is not an examples/learn file: " + b.splitlines()[0]) for n in srcs: if n not in used: fail(f"learn {n}", "not shown in docs/LEARN.md") if not bad: ok(f"docs/LEARN.md: {len(blocks)} blocks, all match examples/learn") sys.exit(1 if bad else 0)