From cee746250bac6057926a86f7b4316b93923508e1 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 6 Jul 2026 13:04:35 -0400 Subject: [PATCH] feat(opcodes): emit opcodes.json, opcode-reference.md, coverage Co-Authored-By: Claude Opus 4.8 (1M context) --- tools/opcodes_build.py | 73 ++++++++++++++++++++++++++++++++++++++++++ tools/test_opcodes.py | 12 +++++++ 2 files changed, 85 insertions(+) diff --git a/tools/opcodes_build.py b/tools/opcodes_build.py index 51dff1c..06ece53 100644 --- a/tools/opcodes_build.py +++ b/tools/opcodes_build.py @@ -122,6 +122,74 @@ def emit_inferred_py(model: M.Model) -> str: lines.append("}") return "\n".join(lines) + "\n" +def emit_json(model: M.Model) -> str: + rev = M.dependents(model) + out = {"meta": model.meta, "opcodes": [], + "dependents": {"0x%x" % k: ["0x%x" % d for d in v] for k, v in rev.items() if v}} + for op, oc in sorted(model.opcodes.items()): + e = {"op": "0x%x" % op, "label": oc.label, "argc": oc.argc, + "code_target_args": oc.code_target_args, "abi_source": oc.abi_source} + s = oc.semantics + if s: + e["semantics"] = {"name": s.name, "category": s.category, "summary": s.summary, + "noop_headless": s.noop_headless, "source": s.source, + "confidence": s.confidence, "depends_on": ["0x%x" % d for d in s.depends_on], + "evidence": s.evidence, "details": s.details, "args": s.args} + out["opcodes"].append(e) + return json.dumps(out, ensure_ascii=False, indent=2) + "\n" + +def emit_reference_md(model: M.Model) -> str: + rev = M.dependents(model) + L = ["", + "# Opcode Reference (generated)", "", + f"{len(model.opcodes)} opcodes used by Himegari. Source of truth: `vm-map/opcodes.toml`.", ""] + by_cat = collections.defaultdict(list) + for op, oc in model.opcodes.items(): + cat = oc.semantics.category if oc.semantics else "unknown" + by_cat[cat].append(op) + for cat in sorted(by_cat): + L += [f"## {cat}", ""] + for op in sorted(by_cat[cat]): + oc = model.opcodes[op] + s = oc.semantics + name = s.name if s else oc.label + L.append(f"### 0x{op:x} `{name}` ({oc.label}, argc {oc.argc})") + if s: + L.append(f"- **summary:** {s.summary}" if s.summary else "- **summary:** —") + L.append(f"- **grounding:** source={s.source}, confidence={s.confidence}" + + (f", noop_headless={s.noop_headless}" if s.noop_headless else "")) + if s.depends_on: + L.append("- **depends on:** " + ", ".join("0x%x" % d for d in s.depends_on)) + if rev.get(op): + L.append("- **depended on by:** " + ", ".join("0x%x" % d for d in rev[op])) + if s.evidence: + L.append(f"- **evidence:** {s.evidence}") + if s.details: + L += ["", s.details] + L.append("") + return "\n".join(L) + "\n" + +def emit_coverage_md(model: M.Model) -> str: + by_src = collections.Counter() + by_conf = collections.Counter() + by_cat = collections.Counter() + named = 0 + for oc in model.opcodes.values(): + s = oc.semantics + if s: + by_src[s.source] += 1 + by_conf[s.confidence] += 1 + by_cat[s.category] += 1 + if s.name != oc.label: + named += 1 + L = ["", "# Opcode Coverage (generated)", "", + f"- opcodes: {len(model.opcodes)}", f"- given a distinct mnemonic: {named}", "", + "## by source", ""] + L += [f"- {k}: {v}" for k, v in sorted(by_src.items())] + L += ["", "## by confidence", ""] + [f"- {k}: {by_conf[k]}" for k in ("high", "med", "low")] + L += ["", "## by category", ""] + [f"- {k}: {v}" for k, v in sorted(by_cat.items())] + return "\n".join(L) + "\n" + def main(argv=None): ap = argparse.ArgumentParser() ap.add_argument("--bootstrap", action="store_true") @@ -144,6 +212,11 @@ def main(argv=None): return 1 (paths.REPO / "tools" / "age_opcodes_himegari.py").write_text(emit_inferred_py(model), encoding="utf-8") print("build: wrote tools/age_opcodes_himegari.py") + paths.BUILD.mkdir(parents=True, exist_ok=True) + (paths.BUILD / "opcodes.json").write_text(emit_json(model), encoding="utf-8") + (paths.REPO / "docs" / "opcode-reference.md").write_text(emit_reference_md(model), encoding="utf-8") + (paths.BUILD / "opcode-coverage.md").write_text(emit_coverage_md(model), encoding="utf-8") + print("build: wrote build/opcodes.json, docs/opcode-reference.md, build/opcode-coverage.md") return 0 if args.lint: errors, warnings = M.lint(M.load(tp)) diff --git a/tools/test_opcodes.py b/tools/test_opcodes.py index c98d9f3..9fe95da 100644 --- a/tools/test_opcodes.py +++ b/tools/test_opcodes.py @@ -141,11 +141,23 @@ def test_emit_inferred(): check(0x90 in inf and inf[0x90]["name"] == "hotspot-branch", "generated INFERRED[0x90]['name'] correct") check(0x1f4 in inf, "named marker 0x1f4 (name != label) included") +def test_emit_views(): + import opcodes_build as B, json as _json + m = M.load(write_tmp(FIXTURE)) + j = _json.loads(B.emit_json(m)) + check(j["dependents"]["0x1f4"] == ["0x90"], "json dependents index correct") + check(any(o["op"] == "0x90" for o in j["opcodes"]), "json lists opcode 0x90") + md = B.emit_reference_md(m) + check("hotspot-branch" in md and "depended on by" in md.lower(), "reference md has entry + dependents line") + cov = B.emit_coverage_md(m) + check("investigation" in cov, "coverage md breaks down by source") + def main(): test_load() test_lint() test_bootstrap() test_emit_inferred() + test_emit_views() print("FAILURES:", len(FAILS)) return 1 if FAILS else 0