feat(opcodes): linter (dangling-ref, confidence-ceiling, vocabulary)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-06 13:01:20 -04:00
parent 9f15aa0336
commit 503eb70359
2 changed files with 88 additions and 0 deletions

View File

@@ -67,6 +67,35 @@ def load(path) -> Model:
)
return Model(meta=data.get("meta", {}), opcodes=ops)
def lint(model: Model) -> tuple[list[str], list[str]]:
"""Return (errors, warnings). Errors: bad vocabulary, dangling depends_on.
Warnings: confidence exceeds the minimum confidence among its dependencies."""
errors: list[str] = []
warnings: list[str] = []
ops = model.opcodes
for op, oc in sorted(ops.items()):
s = oc.semantics
if not s:
continue
tag = f"0x{op:x}"
if s.category not in CATEGORIES:
errors.append(f"{tag}: bad category {s.category!r}")
if s.source not in SOURCES:
errors.append(f"{tag}: bad source {s.source!r}")
if s.confidence not in CONFIDENCE:
errors.append(f"{tag}: bad confidence {s.confidence!r}")
for dep in s.depends_on:
if dep not in ops:
errors.append(f"{tag}: depends_on missing opcode 0x{dep:x}")
if s.confidence in CONFIDENCE:
dep_confs = [CONFIDENCE[ops[d].semantics.confidence]
for d in s.depends_on
if d in ops and ops[d].semantics
and ops[d].semantics.confidence in CONFIDENCE]
if dep_confs and CONFIDENCE[s.confidence] > min(dep_confs):
warnings.append(f"{tag}: confidence {s.confidence!r} exceeds dependency ceiling")
return errors, warnings
def dependents(model: Model) -> dict[int, list[int]]:
"""Reverse of depends_on: op -> [ops whose semantics depend on it]."""
rev: dict[int, list[int]] = {op: [] for op in model.opcodes}

View File

@@ -58,8 +58,67 @@ def test_load():
rev = M.dependents(m)
check(rev.get(0x1f4) == [0x90], "dependents: 0x1f4 depended on by 0x90")
DANGLING = '''
[[opcode]]
op = 0x10
label = "x"
argc = 0
[opcode.semantics]
name = "a"
category = "compute"
source = "inference"
confidence = "low"
depends_on = [0x99]
'''
CEILING = '''
[[opcode]]
op = 0x10
label = "x"
argc = 0
[opcode.semantics]
name = "low-op"
category = "compute"
source = "kelebek"
confidence = "low"
[[opcode]]
op = 0x11
label = "y"
argc = 0
[opcode.semantics]
name = "high-op"
category = "compute"
source = "inference"
confidence = "high"
depends_on = [0x10]
'''
BADVOCAB = '''
[[opcode]]
op = 0x10
label = "x"
argc = 0
[opcode.semantics]
name = "a"
category = "bogus"
source = "inference"
confidence = "low"
'''
def test_lint():
e, w = M.lint(M.load(write_tmp(DANGLING)))
check(any("0x99" in m for m in e), "dangling depends_on is an error")
e, w = M.lint(M.load(write_tmp(CEILING)))
check(any("0x11" in m for m in w), "confidence-ceiling violation is a warning")
check(e == [], "confidence-ceiling case has no errors")
e, w = M.lint(M.load(write_tmp(BADVOCAB)))
check(any("category" in m for m in e), "unknown category is an error")
e, w = M.lint(M.load(write_tmp(FIXTURE)))
check(e == [], "clean fixture has no lint errors")
def main():
test_load()
test_lint()
print("FAILURES:", len(FAILS))
return 1 if FAILS else 0