nx_field_of_struct_gate.nx source
↩ module page · 116 lines · 6792 B
1// nx_field_of_struct_gate.nx -- LN29 (lang.plan, 2026-09-02): A FIELD NAME MUST BELONG TO THE STRUCT IT IS
2// READ FROM. End-to-end over the PROMOTED compiler: two fixtures are assembled at runtime in /tmp/<gate>/
3// (never a file a source census could mistake for an organ), the compiler is forked on each with stderr
4// captured to a file, and the teeth read the captured bytes:
5// fx_bad reads p.c on a struct declaring a and b -> MUST be refused, naming the struct, the field and
6// the fields it really declares (the teaching voice: where, caret, why, fix)
7// fx_ok reads p.a and p.b on the same struct -> MUST compile with no error line (the positive control)
8// The refusal is the LN29 contract; the control is what keeps the gate from passing on a compiler that
9// refuses everything. The "corpus builds unchanged" half of the done-rule is nx_cc_equiv_gate's job
10// (10 rows + self-host), deliberately not duplicated here (one ruler per question).
11// nx_field_of_struct_gate -- verdict in the exit code (gv_verdict)
12// license_tier: ORIGINAL layer: lang module: nishi-core.lang.field_of_struct_gate
13import "nx_syscalls.nx"
14import "nx_gate_verdict.nx"
15
16const FG_DIR: *u8 = "/tmp/nx_field_of_struct_gate\x00" as *u8
17const FG_BAD: *u8 = "/tmp/nx_field_of_struct_gate/fx_bad.nx\x00" as *u8
18const FG_OK: *u8 = "/tmp/nx_field_of_struct_gate/fx_ok.nx\x00" as *u8
19const FG_BAD_ERR: *u8 = "/tmp/nx_field_of_struct_gate/fx_bad.err\x00" as *u8
20const FG_OK_ERR: *u8 = "/tmp/nx_field_of_struct_gate/fx_ok.err\x00" as *u8
21const FG_DEVNULL: *u8 = "/dev/null\x00" as *u8
22const FG_CC_NAS: *u8 = "buildroot/_offc/nx_cc_sovereign.elf\x00" as *u8 // NAS gate CWD = nishihost root
23const FG_CC_LAP: *u8 = "_offc/nx_cc_sovereign.elf\x00" as *u8 // laptop CWD = nxc2 root
24const FG_CAP: i64 = 65536
25const FG_MODE: i64 = 420
26
27func fg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
28func fg_w(s: *u8) -> i64 { sys_write(1, s, fg_slen(s)); return 0 }
29func fg_find(b: *u8, n: i64, pat: *u8) -> i64 {
30 let pl: i64 = fg_slen(pat)
31 if pl <= 0 { return 0 - 1 }
32 var i: i64 = 0
33 while i + pl <= n {
34 var j: i64 = 0; var ok: i64 = 1
35 while j < pl { if b[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } }
36 if ok == 1 { return i }
37 i = i + 1
38 }
39 return 0 - 1
40}
41func fg_write_file(path: *u8, body: *u8) -> i64 {
42 let fd: i64 = sys_openat_wr(path, FG_MODE)
43 if fd < 0 { return 0 - 1 }
44 let n: i64 = fg_slen(body)
45 sys_write(fd, body, n)
46 sys_close(fd)
47 return n
48}
49// fork the compiler on src with stderr -> errpath; returns the child's exit code, -1 if it could not fork/exec.
50func fg_compile(cc: *u8, src: *u8, errpath: *u8) -> i64 {
51 let pid: i64 = sys_fork()
52 if pid < 0 { return 0 - 1 }
53 if pid == 0 {
54 let dn: i64 = sys_openat_wr(FG_DEVNULL, FG_MODE)
55 if dn >= 0 { sys_dup3(dn, 1, 0) }
56 let ef: i64 = sys_openat_wr(errpath, FG_MODE)
57 if ef >= 0 { sys_dup3(ef, 2, 0) }
58 let argv: *i64 = sys_mmap(32) as *i64
59 argv[0] = cc as i64; argv[1] = src as i64; argv[2] = 0
60 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
61 sys_execve(cc, argv, envp)
62 sys_exit(127)
63 }
64 let st: *i64 = sys_mmap(16) as *i64
65 sys_wait4(pid, st, 0)
66 return (st[0] >> 8) & 0xff
67}
68func fg_read(path: *u8, buf: *u8, cap: i64) -> i64 {
69 let fd: i64 = sys_openat_rd(path)
70 if fd < 0 { return 0 - 1 }
71 var tot: i64 = 0; var go: i64 = 1
72 while go == 1 {
73 let n: i64 = sys_read(fd, ((buf as i64) + tot) as *u8, cap - tot)
74 if n <= 0 { go = 0 } else { tot = tot + n; if tot >= cap { go = 0 } }
75 }
76 sys_close(fd)
77 return tot
78}
79// the promoted compiler, wherever this gate runs from (two-root probe, announced).
80func fg_pick_cc() -> *u8 {
81 let fd: i64 = sys_openat_rd(FG_CC_NAS)
82 if fd >= 0 { sys_close(fd); return FG_CC_NAS }
83 return FG_CC_LAP
84}
85
86func main() -> i64 {
87 let c: *i64 = gv_ctr()
88 sys_mkdir(FG_DIR, 493)
89 let cc: *u8 = fg_pick_cc()
90 fg_w(" compiler=" as *u8); fg_w(cc); fg_w("\n" as *u8)
91 // fixtures assembled at RUNTIME; no imports, so they resolve from any CWD (the crash guard's absence
92 // is a named non-fatal notice in the driver, not an error).
93 let wb: i64 = fg_write_file(FG_BAD, "struct Pair { a: i64, b: i64 }\nfunc main() -> i64 {\n let p: *Pair = 4096 as *Pair\n p.a = 1\n return p.c\n}\n" as *u8)
94 let wo: i64 = fg_write_file(FG_OK, "struct Pair { a: i64, b: i64 }\nfunc main() -> i64 {\n let p: *Pair = 4096 as *Pair\n p.a = 1\n p.b = 2\n return p.a + p.b\n}\n" as *u8)
95 gv_check("fixtures-written-to-tmp-gate-dir" as *u8, (wb > 0) & (wo > 0), c)
96
97 let rc_bad: i64 = fg_compile(cc, FG_BAD, FG_BAD_ERR)
98 let rc_ok: i64 = fg_compile(cc, FG_OK, FG_OK_ERR)
99 let eb: *u8 = sys_mmap(FG_CAP); let nb: i64 = fg_read(FG_BAD_ERR, eb, FG_CAP - 1)
100 let eo: *u8 = sys_mmap(FG_CAP); let no: i64 = fg_read(FG_OK_ERR, eo, FG_CAP - 1)
101 fg_w(" bad: rc=" as *u8); gv_num(rc_bad); fg_w(" stderr_bytes=" as *u8); gv_num(nb)
102 fg_w(" ok: rc=" as *u8); gv_num(rc_ok); fg_w(" stderr_bytes=" as *u8); gv_num(no); fg_w("\n" as *u8)
103 if nb > 0 { fg_w(" bad stderr head: " as *u8); var k: i64 = 0; while k < nb { if k < 160 { if eb[k] == (10 as u8) { k = nb } else { sys_write(1, ((eb as i64) + k) as *u8, 1) } } k = k + 1 } fg_w("\n" as *u8) }
104
105 gv_check("fixture-reached-the-compiler-both-ran" as *u8, (rc_bad >= 0) & (rc_ok >= 0) & (rc_bad != 127) & (rc_ok != 127), c)
106 gv_check("bad-is-refused-nonzero-exit" as *u8, rc_bad != 0, c)
107 gv_check("bad-names-the-struct-and-the-field" as *u8, fg_find(eb, nb, "struct 'Pair' has no field named 'c'" as *u8) >= 0, c)
108 gv_check("bad-carries-the-location-anchor" as *u8, fg_find(eb, nb, "error at " as *u8) >= 0, c)
109 gv_check("bad-carries-why-the-build-stopped" as *u8, fg_find(eb, nb, "why the build stopped" as *u8) >= 0, c)
110 gv_check("bad-fix-lists-the-real-fields" as *u8, fg_find(eb, nb, "fix: use one of the fields this struct declares: a, b" as *u8) >= 0, c)
111 gv_check("bad-writes-no-program" as *u8, fg_find(eb, nb, "wrote no program" as *u8) >= 0, c)
112 gv_check("control-declared-fields-compile-exit-0" as *u8, rc_ok == 0, c)
113 gv_check("control-declared-fields-print-no-error-at" as *u8, fg_find(eo, no, "error at " as *u8) < 0, c)
114 gv_check("neg-control-the-refusal-is-specific-not-blanket" as *u8, fg_find(eo, no, "has no field named" as *u8) < 0, c)
115 return gv_verdict("FIELD-OF-STRUCT-GATE" as *u8, c, "LN29: an undeclared field on a declared struct is refused by name with the real fields listed; declared fields compile" as *u8)
116}