nx_str_gate.nx source
↩ module page · 95 lines · 4972 B
1// nx_str_gate.nx -- the gate for the string vocabulary 109 modules import.
2// WHY: nx_gensota's gen-3 worklist ranked it #3 by importers with no gate sibling. It DOES
3// carry a self-test -- inside its own main() -- and that is precisely the problem:
4// expand_imports STRIPS func main from every non-root file, so that self-test runs ONLY when
5// someone deliberately builds nx_str.nx as an entry point, which nothing does routinely, and
6// NO rollup can read its result.
7// ★LAW: A SELF-TEST INSIDE THE MODULE'S OWN main() IS STRIPPED FROM EVERY CONSUMER AND
8// INVISIBLE TO EVERY RULER -- it is documentation that happens to compile.
9// This gate re-derives the contract from OUTSIDE, in the ruler-readable shape.
10// ⚠FINDING PINNED, NOT SILENTLY FIXED (T9/T10): nx_str_chr(s,0) returns the TERMINATOR index
11// (C strchr convention) while nx_str_rchr(s,0) returns -1. The pair DISAGREES on the NUL
12// convention. 109 importers may depend on either; this gate PINS today's behaviour so any
13// future change is a loud diff, and the asymmetry is declared rather than quietly aligned.
14// license_tier: ORIGINAL expect_exit: 0 No hw writes (Rule 26).
15import "nx_syscalls.nx"
16import "nx_gate_verdict.nx"
17import "nx_str.nx"
18
19const NSG_BUF: i64 = 64
20
21func nsg_lit3(p: *u8, a: i64, b: i64, c: i64) -> i64 {
22 p[0] = a as u8; p[1] = b as u8; p[2] = c as u8; p[3] = 0 as u8
23 return 0
24}
25
26func main() -> i64 {
27 let ctr: *i64 = gv_ctr()
28 gv_head("NX-STR-GATE -- the string vocabulary 109 modules import, verified from OUTSIDE" as *u8)
29
30 let foo: *u8 = sys_mmap(NSG_BUF)
31 nsg_lit3(foo, 0x66, 0x6F, 0x6F) // "foo"
32 let bar: *u8 = sys_mmap(NSG_BUF)
33 nsg_lit3(bar, 0x62, 0x61, 0x72) // "bar"
34 let empty: *u8 = sys_mmap(NSG_BUF)
35 empty[0] = 0 as u8
36 let foobar: *u8 = sys_mmap(NSG_BUF)
37 nx_str_cpy(foobar, foo)
38 nx_str_cat(foobar, bar) // "foobar"
39
40 var t1: i64 = 0
41 if nx_str_len(foo) == 3 { if nx_str_len(empty) == 0 { if nx_str_len(foobar) == 6 { t1 = 1 } } }
42 gv_check("T1 len: 3 / 0 (empty) / 6 (after cpy+cat)" as *u8, t1, ctr)
43
44 var t2: i64 = 0
45 if nx_str_eq(foo, foo) == 1 { if nx_str_eq(foo, bar) == 0 { if nx_str_eq(foo, foobar) == 0 { t2 = 1 } } }
46 gv_check("T2 eq: reflexive; differs; PREFIX is not equality" as *u8, t2, ctr)
47
48 var t3: i64 = 0
49 if nx_str_cmp(foo, foo) == 0 { if nx_str_cmp(bar, foo) < 0 { if nx_str_cmp(foo, bar) > 0 { t3 = 1 } } }
50 gv_check("T3 cmp: 0 equal, sign follows byte order (bar<foo)" as *u8, t3, ctr)
51
52 var t4: i64 = 0
53 if nx_str_cmp(foo, foobar) < 0 { if nx_str_cmp(foobar, foo) > 0 { t4 = 1 } }
54 gv_check("T4 cmp: a PREFIX sorts before its extension, both directions" as *u8, t4, ctr)
55
56 var t5: i64 = 0
57 if nx_str_starts_with(foobar, foo) == 1 { if nx_str_starts_with(foo, foobar) == 0 { if nx_str_starts_with(foo, empty) == 1 { t5 = 1 } } }
58 gv_check("T5 starts_with: true / longer-prefix false / EMPTY prefix is true" as *u8, t5, ctr)
59
60 var t6: i64 = 0
61 if nx_str_ends_with(foobar, bar) == 1 { if nx_str_ends_with(foobar, foo) == 0 { if nx_str_ends_with(foo, empty) == 1 { t6 = 1 } } }
62 gv_check("T6 ends_with: true / a PREFIX is not a suffix / EMPTY suffix is true" as *u8, t6, ctr)
63
64 var t7: i64 = 0
65 if nx_str_str(foobar, bar) == 3 { if nx_str_str(foo, bar) == (0 - 1) { if nx_str_str(foo, empty) == 0 { t7 = 1 } } }
66 gv_check("T7 str: offset 3 / absent -1 / EMPTY needle matches at 0" as *u8, t7, ctr)
67
68 let dst: *u8 = sys_mmap(NSG_BUF)
69 nx_str_memset(dst, 0x41, 4)
70 dst[4] = 0 as u8
71 var t8: i64 = 0
72 if nx_str_len(dst) == 4 { if dst[0] == (0x41 as u8) { if dst[3] == (0x41 as u8) { t8 = 1 } } }
73 nx_str_memcpy(dst, foo, 3)
74 if t8 == 1 { if nx_str_memcmp(dst, foo, 3) != 0 { t8 = 0 } }
75 gv_check("T8 memset fills exactly n; memcpy then memcmp round-trips" as *u8, t8, ctr)
76
77 // PINNED ASYMMETRY -- see header. Not an assertion that this is RIGHT, an assertion that
78 // it is what 109 importers get today.
79 var t9: i64 = 0
80 if nx_str_chr(foobar, 0x62) == 3 { if nx_str_chr(foo, 0x62) == (0 - 1) { if nx_str_chr(foo, 0) == 3 { t9 = 1 } } }
81 gv_check("T9 chr: found / absent -1 / PINNED: chr(s,0) returns the TERMINATOR index" as *u8, t9, ctr)
82
83 var t10: i64 = 0
84 if nx_str_rchr(foobar, 0x6F) == 2 { if nx_str_rchr(foo, 0) == (0 - 1) { t10 = 1 } }
85 gv_check("T10 rchr: LAST occurrence / PINNED: rchr(s,0) returns -1 (DISAGREES with chr)" as *u8, t10, ctr)
86
87 // NEGATIVE CONTROL: the comparators must be capable of saying NO.
88 var t11: i64 = 0
89 if nx_str_eq(foo, bar) == 0 { if nx_str_str(foo, bar) < 0 { if nx_str_ends_with(foo, bar) == 0 { t11 = 1 } } }
90 gv_check("T11 NEG-CONTROL: unrelated strings REJECTED by eq, str and ends_with" as *u8, t11, ctr)
91
92 let rc: i64 = gv_verdict("STR-GATE" as *u8, ctr, "vocabulary verified from outside; NUL asymmetry pinned" as *u8)
93 sys_exit(rc)
94 return rc
95}