nx_macro_axis_gate.nx source
↩ module page · 116 lines · 4973 B
1// nx_macro_axis_gate.nx -- mechanically prove the BACKEND-OWNED TARGET AXIS of the self-host
2// preprocessor. Closes debt 1785516163, which asked for exactly this: a gate that FAILS if a compiled
3// corpus ever resolves TARGET_X86_64 as DEFINED, so the pin is held by a MECHANISM instead of a comment.
4//
5// WHY THIS MATTERS MORE THAN IT LOOKS. The x86 self-host emits through x86ctx_rv64_to_x86_64_syscall,
6// which expects source to carry RV64 syscall numbers and translates them at emit time. So:
7//
8// TARGET_X86_64 MUST be UNDEFINED -> the @ifndef branch (RV64 numbers) is the live one
9// TARGET_RV64 MUST be DEFINED -> the source axis, the exact complement
10//
11// If someone fixes the preprocessor by predefining TARGET_X86_64 as an ordinary macro -- the natural
12// looking change when adding a macro table -- the raw-x86 branch of nx_syscalls / nx_hal / nx_dirent /
13// nx_poll / nx_probe / nx_fcntl / nx_self_build switches on, and EVERY syscall const is then translated
14// TWICE. Silent ecosystem-wide corruption, not a build error: the binaries still link and still run,
15// they just call the wrong kernel entry points. A comment cannot stop that. This gate can.
16//
17// NON-VACUITY BY CONSTRUCTION. Every block that MUST be dropped contains a poison identifier that does
18// not exist anywhere in the corpus. If a drop path ever fails, the poison reaches the parser and THE
19// BUILD FAILS. So this gate cannot pass vacuously -- a preprocessor that ignored @ifdef entirely could
20// not compile this file at all.
21//
22// expect_exit: 0 license_tier: ORIGINAL
23
24import "nx_kernel_v2.nx"
25
26// ===== AXIS 1: TARGET_X86_64 MUST BE UNDEFINED =====
27@ifdef TARGET_X86_64
28func axis_x86_state() -> nx_int { return BROKEN_X86_AXIS_LEAKED }
29@endif
30
31@ifndef TARGET_X86_64
32func axis_x86_state() -> nx_int { return 1 }
33@endif
34
35// ===== AXIS 2: TARGET_RV64 MUST BE DEFINED (the complement) =====
36@ifdef TARGET_RV64
37func axis_rv64_state() -> nx_int { return 1 }
38@endif
39
40@ifndef TARGET_RV64
41func axis_rv64_state() -> nx_int { return BROKEN_RV64_AXIS_MISSING }
42@endif
43
44// ===== AXIS 3: NXC_VERSION MUST BE DEFINED (compiler identity) =====
45@ifdef NXC_VERSION
46func axis_nxc_state() -> nx_int { return 1 }
47@endif
48
49@ifndef NXC_VERSION
50func axis_nxc_state() -> nx_int { return BROKEN_NXC_VERSION_MISSING }
51@endif
52
53// ===== AXIS 4: AN ARBITRARY UNDEFINED NAME MUST RESOLVE UNDEFINED =====
54// Regression tooth for the ORIGINAL defect: the preprocessor compared against exactly one hardcoded
55// string, so every OTHER name resolved as DEFINED and @ifdef ANYTHING kept its block.
56@ifdef NX_AXIS_NAME_THAT_IS_NEVER_DEFINED
57func axis_unknown_state() -> nx_int { return BROKEN_UNKNOWN_NAME_TREATED_AS_DEFINED }
58@endif
59
60@ifndef NX_AXIS_NAME_THAT_IS_NEVER_DEFINED
61func axis_unknown_state() -> nx_int { return 1 }
62@endif
63
64// ===== AXIS 5: @undef MUST ACTUALLY RETRACT =====
65@macro NX_AXIS_TEMP 1
66
67@ifdef NX_AXIS_TEMP
68func axis_undef_before() -> nx_int { return 1 }
69@endif
70
71@undef NX_AXIS_TEMP
72
73@ifdef NX_AXIS_TEMP
74func axis_undef_after() -> nx_int { return BROKEN_UNDEF_DID_NOT_RETRACT }
75@endif
76
77@ifndef NX_AXIS_TEMP
78func axis_undef_after() -> nx_int { return 1 }
79@endif
80
81func main() -> nx_exit {
82 println("=== nx_macro_axis_gate -- backend-owned target axis (debt 1785516163) ===" as *u8)
83
84 let a1: nx_int = axis_x86_state()
85 if a1 != 1 { println("T1 x86_undefined FAIL" as *u8); return 1 }
86 println("T1 x86_undefined PASS TARGET_X86_64 resolves UNDEFINED (RV64 branch is live)" as *u8)
87
88 let a2: nx_int = axis_rv64_state()
89 if a2 != 1 { println("T2 rv64_defined FAIL" as *u8); return 2 }
90 println("T2 rv64_defined PASS TARGET_RV64 resolves DEFINED (source axis)" as *u8)
91
92 let a3: nx_int = axis_nxc_state()
93 if a3 != 1 { println("T3 nxc_version FAIL" as *u8); return 3 }
94 println("T3 nxc_version PASS NXC_VERSION resolves DEFINED (compiler identity)" as *u8)
95
96 let a4: nx_int = axis_unknown_state()
97 if a4 != 1 { println("T4 unknown_undefined FAIL" as *u8); return 4 }
98 println("T4 unknown_undefined PASS an undeclared name resolves UNDEFINED, not defined" as *u8)
99
100 let a5: nx_int = axis_undef_before()
101 if a5 != 1 { println("T5 undef_before FAIL" as *u8); return 5 }
102 println("T5 undef_before PASS @ifdef before @undef kept its block" as *u8)
103
104 let a6: nx_int = axis_undef_after()
105 if a6 != 1 { println("T6 undef_after FAIL" as *u8); return 6 }
106 println("T6 undef_after PASS @undef retracted; later @ifdef dropped its block" as *u8)
107
108 println("" as *u8)
109 println("=== DROP PROOF (compile-time, no runtime check possible) ===" as *u8)
110 println("Five blocks above MUST be dropped, each holding a poison identifier that" as *u8)
111 println("exists nowhere in the corpus. Successful COMPILATION is the verdict --" as *u8)
112 println("this gate cannot pass vacuously." as *u8)
113 println("" as *u8)
114 println("GATE VERDICT: GREEN 6/6" as *u8)
115 return 0
116}