~james/span

perf(cli): compile binary output and assembly report once

commit
de502ca765320a4ac82d4bce88e01936c82bc498 browse tree
parent
dd6b9d1661bbb14e3dfa70ecdba2d25593e72eb8
author
james <j@cpl0.zip>
signature
Verified ~james signed with a key registered by ~james
date
2026-10-31 11:55 UTC

4 files changed, +21 −7

cli/driver.ML modified

@@ -35,13 +35,12 @@ fun run args =
3535 | ["disassemble", file] => output (Span.disassemble (chars (read file)))
3636 | ["assemble", file, "-o", destination] =>
3737 let
38- val input = chars (read file)
39- val (ok, bytes) = Span.binary input
38+ val ((ok, bytes), report) = Span.artifact (chars (read file))
4039 in
4140 if ok then
4241 (write destination (text bytes);
43- output (Span.process [chars "assemble"] input))
44- else output (false, bytes)
42+ output (true, report))
43+ else output (false, report)
4544 end
4645 | ["run", file] => output (Span.process (map chars ["run", "4096"]) (chars (read file)))
4746 | ["run", file, fuel] => output (Span.process (map chars ["run", fuel]) (chars (read file)))

src/Export.thy modified

@@ -6,6 +6,6 @@ definition ascii :: "integer \<Rightarrow> char" where "ascii = char_of"
66
77 definition ordinal :: "char \<Rightarrow> integer" where "ordinal = of_char"
88
9-export_code process binary disassemble ascii ordinal in SML module_name Span file_prefix span
9+export_code process binary artifact disassemble ascii ordinal in SML module_name Span file_prefix span
1010
1111 end

src/Frontend.thy modified

@@ -237,4 +237,15 @@ definition process :: "string list \<Rightarrow> string \<Rightarrow> bool \<tim
237237 case checked p of Error e \<Rightarrow> (False, (if args = [''trace''] then trace p else []) @ e @ newline)
238238 | Ok bs \<Rightarrow> inspect args p bs)"
239239
240+definition artifact :: "string \<Rightarrow> (bool \<times> string) \<times> string" where
241+ "artifact s = (case source s of Error e \<Rightarrow> ((False, e @ newline), e @ newline)
242+ | Ok p \<Rightarrow> case checked p of Error e \<Rightarrow> ((False, e @ newline), e @ newline)
243+ | Ok bs \<Rightarrow> ((True, map char_of_nat bs), summary p bs @ hex bs @ newline))"
244+
245+theorem artifact_binary: "fst (artifact s) = binary s"
246+ by (auto simp: artifact_def binary_def compile_def split: result.splits)
247+
248+theorem artifact_report: "(fst (fst (artifact s)), snd (artifact s)) = process [''assemble''] s"
249+ by (auto simp: artifact_def process_def inspect_def Let_def split: result.splits)
250+
240251 end

tests/cli.py modified

@@ -148,7 +148,8 @@ def main():
148148 expected = rows[pc][0] if pc < length else len(out.read_bytes())
149149 report = cli("run", "-", "256", text=text)
150150 check(f"pc={expected} acc={acc}\n" in report, f"execution mismatch in case {case}")
151- cli("assemble", "examples/countdown.span", "-o", out)
151+ report = cli("assemble", "examples/countdown.span", "-o", out)
152+ check(report == cli("assemble", "examples/countdown.span"), "binary report changed")
152153 check(out.read_bytes() == bytes([1, 1, 1, 2, 17, 130, 16, 123, 3]), "binary output")
153154 check("jmp.8 -5" in cli("disassemble", out), "binary disassembly")
154155 out.write_bytes(bytes([18, 0]))
@@ -156,8 +157,11 @@ def main():
156157 out.write_bytes(bytes([255]))
157158 check("invalid encoding" in cli("disassemble", out, ok=False), "unknown opcode accepted")
158159 out.write_bytes(b"preserve")
159- cli("assemble", "-", "-o", out, text="jmp missing", ok=False)
160+ error = cli("assemble", "-", "-o", out, text="jmp missing", ok=False)
161+ check(error == cli("assemble", "-", text="jmp missing", ok=False), "binary error changed")
160162 check(out.read_bytes() == b"preserve", "failed assembly clobbered output")
163+ cli("assemble", "-", "-o", out, text="")
164+ check(out.read_bytes() == b"", "empty binary output")
161165 print(f"{CHECKS} checks passed, including 36 exhaustive layout comparisons")
162166
163167