code wiki / _hdl_build / nx_emit_guard.nx
nx_emit_guard.nx source
↩ module page · 61 lines · 2507 B
1// nx_emit_guard.nx -- the ONE set of guards every emitter CLI in this lane uses (rule 15: written twice
2// is once too many, and these encode a LAW rather than a convenience).
3//
4// ★WHY: an emitter that writes a SET of files can fail in three ways that all LOOK like success --
5// 1. an unchecked sys_mmap returns null, so every subsequent write goes nowhere;
6// 2. the emitter produces a technically-valid but empty page (a few dozen bytes);
7// 3. individual writes are checked, but nobody asks afterwards whether the SET actually exists.
8// (3) is the one that bit this lane: refine's per-file writes were fail-loud, yet a run that produced
9// zero files still printed a success envelope, because nothing verified the set. A tool that emits a set
10// must PROVE the set before it claims success. Dependency-light on purpose (nx_syscalls only) so any
11// emitter can compose it without dragging a page kit in. license_tier: ORIGINAL
12import "nx_syscalls.nx"
13
14// a real generated page is >=13KB in this lane; anything under this floor means the emitter produced
15// nothing usable and the run must abort rather than write a husk.
16const EG_MIN_PAGE: i64 = 2000
17
18func eg_say(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(2, s, n); return 0 }
19
20// allocate or die loudly. `what` names the buffer so the failure says which one.
21func eg_buf(size: i64, what: *u8) -> *u8 {
22 let p: *u8 = sys_mmap(size)
23 if (p as i64) == 0 {
24 eg_say("EMIT-GUARD FAIL: allocation returned null for " as *u8)
25 eg_say(what)
26 eg_say("\n" as *u8)
27 sys_exit(6)
28 }
29 return p
30}
31
32// a page shorter than the floor is a husk, not a page.
33func eg_assert_size(len: i64, what: *u8) -> i64 {
34 if len < EG_MIN_PAGE {
35 eg_say("EMIT-GUARD FAIL: emitted artifact is impossibly small: " as *u8)
36 eg_say(what)
37 eg_say("\n" as *u8)
38 sys_exit(7)
39 }
40 return len
41}
42
43// does this path open for reading?
44func eg_have(path: *u8) -> i64 {
45 let fd: i64 = sys_openat_rd(path)
46 if fd < 0 { return 0 }
47 sys_close(fd)
48 return 1
49}
50
51// THE SET ASSERTION: the caller loops its planned outputs through this before printing success.
52// A run that wrote nothing now exits 8 instead of reporting a job well done.
53func eg_assert_present(path: *u8) -> i64 {
54 if eg_have(path) == 0 {
55 eg_say("EMIT-GUARD FAIL: post-write check, missing " as *u8)
56 eg_say(path)
57 eg_say("\n" as *u8)
58 sys_exit(8)
59 }
60 return 1
61}