code wiki / _hdl_build / nx_record_tsv_gate.nx
nx_record_tsv_gate.nx source
↩ module page · 150 lines · 6513 B
1// nx_record_tsv_gate.nx -- referee for the TSV <-> NXR1 compatibility bridge (seq1326 rung 2).
2//
3// T1 IS THE TOOTH THAT MAKES ADOPTION SAFE: a real tab-delimited line survives tsv -> NXR1 -> tsv
4// BYTE-IDENTICAL. Without that, migrating a plane's physical format silently rewrites its data and every
5// legacy reader is a liar. With it, a plane can be stored as NXR1 today and its existing decoders keep
6// reading the exact same bytes (rule 19) until each is migrated deliberately.
7//
8// T5 IS THE TOOTH THAT KEEPS THE BRIDGE HONEST: a record holding a value TSV cannot represent must be
9// REFUSED at render time, not silently emitted as extra columns. T6 is its non-vacuity partner -- the same
10// record with the offending byte removed MUST render fine, proving T5 refuses because of the TAB and not
11// because rendering is simply broken.
12//
13// license_tier: ORIGINAL expect_exit: 0
14import "nx_gate.nx"
15import "nx_record_tsv.nx"
16
17const RG_TEETH: i64 = 8
18const RG_BUF: i64 = 4096
19const RG_A: i64 = 97
20const RG_B: i64 = 98
21const RG_C: i64 = 99
22const RG_X: i64 = 120
23const RG_Y: i64 = 121
24const RG_Z: i64 = 122
25const RG_D4: i64 = 52
26const RG_D2: i64 = 50
27const RG_TAB9: i64 = 9
28const RG_VAL42: i64 = 42
29const RG_DEF: i64 = 0 - 7
30const RG_TINYCAP: i64 = 2
31
32func rg_row(name: *u8, ok: i64) -> i64 {
33 gw(" " as *u8); gw(name)
34 if ok == 1 { gw(" PASS\n" as *u8) } else { gw(" FAIL\n" as *u8) }
35 return 0
36}
37func rg_same(a: *u8, b: *u8, n: i64) -> i64 {
38 var i: i64 = 0
39 var ok: i64 = 1
40 while i < n { if a[i] != b[i] { ok = 0; i = n } else { i = i + 1 } }
41 return ok
42}
43
44func main() -> i64 {
45 let rec: *u8 = sys_mmap(RG_BUF)
46 let out: *u8 = sys_mmap(RG_BUF)
47 let line: *u8 = sys_mmap(RG_BUF)
48 let ty: *u8 = sys_mmap(16)
49 ty[0] = NXR_T_STR as u8
50 ty[1] = NXR_T_I64 as u8
51 ty[2] = NXR_T_STR as u8
52
53 // ---- T1: "abc<TAB>42<TAB>xyz" survives tsv -> NXR1 -> tsv BYTE-IDENTICAL, with the middle column
54 // stored as a REAL i64 in between (not as text passed through untouched).
55 line[0] = RG_A as u8; line[1] = RG_B as u8; line[2] = RG_C as u8
56 line[3] = RG_TAB9 as u8
57 line[4] = RG_D4 as u8; line[5] = RG_D2 as u8
58 line[6] = RG_TAB9 as u8
59 line[7] = RG_X as u8; line[8] = RG_Y as u8; line[9] = RG_Z as u8
60 let rn: i64 = rtv_to_nxr(line, 10, ty, 3, rec)
61 let on: i64 = rtv_to_tsv(rec, rn, 3, out, RG_BUF)
62 var t1: i64 = 0
63 if on == 10 { if rg_same(line, out, 10) == 1 { t1 = 1 } }
64
65 // ---- T2: the middle column really is a TYPED i64, readable by field id without any text parsing.
66 var t2: i64 = 0
67 if nxr_get_i64(rec, rn, 2, RG_DEF) == RG_VAL42 { t2 = 1 }
68
69 // ---- T3: an EMPTY MIDDLE column round-trips ("a<TAB><TAB>c").
70 line[0] = RG_A as u8; line[1] = RG_TAB9 as u8; line[2] = RG_TAB9 as u8; line[3] = RG_C as u8
71 let rn3: i64 = rtv_to_nxr(line, 4, ty, 0, rec)
72 let on3: i64 = rtv_to_tsv(rec, rn3, 3, out, RG_BUF)
73 var t3: i64 = 0
74 if on3 == 4 { if rg_same(line, out, 4) == 1 { t3 = 1 } }
75
76 // ---- T4: a TRAILING EMPTY column round-trips ("a<TAB>b<TAB>") -- the classic off-by-one every
77 // hand-rolled TSV splitter gets wrong by dropping the final empty field.
78 line[0] = RG_A as u8; line[1] = RG_TAB9 as u8; line[2] = RG_B as u8; line[3] = RG_TAB9 as u8
79 let rn4: i64 = rtv_to_nxr(line, 4, ty, 0, rec)
80 var t4: i64 = 0
81 if nxr_count(rec) == 3 {
82 let on4: i64 = rtv_to_tsv(rec, rn4, 3, out, RG_BUF)
83 if on4 == 4 { if rg_same(line, out, 4) == 1 { t4 = 1 } }
84 }
85
86 // ---- T5 REFUSAL: a stored value containing a TAB cannot be rendered as TSV. Must return the error
87 // code, NOT a line that would parse as two columns.
88 let dirty: *u8 = sys_mmap(64)
89 dirty[0] = RG_A as u8; dirty[1] = RG_TAB9 as u8; dirty[2] = RG_B as u8
90 let d: *u8 = sys_mmap(RG_BUF)
91 var od: i64 = nxr_init(d)
92 od = nxr_add(d, od, 1, NXR_T_STR, dirty, 3)
93 var t5: i64 = 0
94 if rtv_to_tsv(d, od, 1, out, RG_BUF) == RTV_ERR_TAB_IN_VALUE { t5 = 1 }
95
96 // ---- T6 NON-VACUITY for T5: the SAME shape without the tab renders fine. If this failed, T5 would
97 // be passing because rendering is broken, not because the tab was caught.
98 let clean: *u8 = sys_mmap(64)
99 clean[0] = RG_A as u8; clean[1] = RG_C as u8; clean[2] = RG_B as u8
100 let e: *u8 = sys_mmap(RG_BUF)
101 var oe: i64 = nxr_init(e)
102 oe = nxr_add(e, oe, 1, NXR_T_STR, clean, 3)
103 var t6: i64 = 0
104 if rtv_to_tsv(e, oe, 1, out, RG_BUF) == 3 { if rg_same(clean, out, 3) == 1 { t6 = 1 } }
105
106 // ---- T7: an ABSENT field renders as an EMPTY column and does NOT shift the columns after it.
107 // Field 2 is never written; field 3 must still land in column 3.
108 let s: *u8 = sys_mmap(RG_BUF)
109 var os: i64 = nxr_init(s)
110 os = nxr_add(s, os, 1, NXR_T_STR, clean, 1)
111 os = nxr_add(s, os, 3, NXR_T_STR, clean, 1)
112 let on7: i64 = rtv_to_tsv(s, os, 3, out, RG_BUF)
113 var t7: i64 = 0
114 if on7 == 4 {
115 if out[0] == (RG_A as u8) { if out[1] == (RG_TAB9 as u8) {
116 if out[2] == (RG_TAB9 as u8) { if out[3] == (RG_A as u8) { t7 = 1 } } } }
117 }
118
119 // ---- T8: a render that would overflow the caller buffer is REFUSED, never truncated.
120 var t8: i64 = 0
121 if rtv_to_tsv(rec, rn4, 3, out, RG_TINYCAP) == RTV_ERR_CAP { t8 = 1 }
122
123 var passes: i64 = 0
124 if t1 == 1 { passes = passes + 1 }
125 if t2 == 1 { passes = passes + 1 }
126 if t3 == 1 { passes = passes + 1 }
127 if t4 == 1 { passes = passes + 1 }
128 if t5 == 1 { passes = passes + 1 }
129 if t6 == 1 { passes = passes + 1 }
130 if t7 == 1 { passes = passes + 1 }
131 if t8 == 1 { passes = passes + 1 }
132 var green: i64 = 0
133 if passes == RG_TEETH { green = 1 }
134
135 gw("=== nx_record_tsv_gate -- TSV<->NXR1 compatibility bridge (seq1326 rung 2) ===\n" as *u8)
136 rg_row("T1-tsv-nxr-tsv-BYTE-IDENTICAL " as *u8, t1)
137 rg_row("T2-middle-column-is-a-REAL-i64 " as *u8, t2)
138 rg_row("T3-empty-middle-column-round-trips " as *u8, t3)
139 rg_row("T4-trailing-empty-column-round-trips " as *u8, t4)
140 rg_row("T5-REFUSES-to-render-TAB-in-value " as *u8, t5)
141 rg_row("T6-NONVACUITY-same-shape-renders-ok " as *u8, t6)
142 rg_row("T7-absent-field-does-NOT-shift-cols " as *u8, t7)
143 rg_row("T8-overflow-REFUSED-never-truncated " as *u8, t8)
144 gw("verdict=" as *u8)
145 if green == 1 { gw("GREEN" as *u8) } else { gw("RED" as *u8) }
146 gw(" passes=" as *u8); gn(passes); gw("/" as *u8); gn(RG_TEETH); gw("\n" as *u8)
147
148 if green == 1 { return 0 }
149 return 1
150}