code wiki / _hdl_build / nx_flip_lib.nx
nx_flip_lib.nx source
↩ module page · 244 lines · 8397 B
1// nx_flip_lib.nx -- THE BASE for the FlipOrgan family (rule #6 OO base, rule #15 DRY, rule #22).
2//
3// NishiLang has no classes, so the base-class contract is expressed as a shared library every organ
4// in the family imports and specialises. Before this, nx_flip_score / _real / _defl / _worklist /
5// _gate each carried their OWN copy of the SAME ~17 primitives under a private prefix (fl_ fr_ fd_
6// fw_ fg_) -- five copies of column parsing, five of integer printing, five of the line-scan idiom.
7// A fix to any one of them fixed only one organ. That does not scale and it is how the family drifts.
8//
9// THE FAMILY CONTRACT every FlipOrgan honours (enforced by nx_flip_gate, 16 cases):
10// 1. summary + `verdict=` FIRST, detail buffered and flushed last (nx_plan_run caps snippets at 200B)
11// 2. FAIL-CLOSED on absent input -- an absent finding/component/observation is a FINDING, not a neutral
12// 3. every threshold read from a plane, never a literal in code (rule #11)
13// 4. integer-only arithmetic, basis points for ratios (no-float substrate)
14// 5. a `verdict=` anchor so the ecosystem judge can read the result (D001)
15//
16// TAB-separated, newline-terminated plane rows are the ONE wire format (rule: planes > tsv).
17// license_tier: ORIGINAL No hw writes (Rule 26).
18import "nx_store_seed_lib.nx"
19import "nx_seg_store.nx"
20import "nx_syscalls.nx"
21
22const FX_TAB: i64 = 9
23const FX_NL: i64 = 10
24const FX_MINUS: i64 = 45
25const FX_D0: i64 = 48
26const FX_D9: i64 = 57
27const FX_BPS: i64 = 10000
28const FX_BUF: i64 = 262144
29const FX_OUT: i64 = 1
30const FX_SCRATCH: i64 = 32
31const FX_PFXCAP: i64 = 256
32const FX_NUMCAP: i64 = 40
33const FX_TMPCAP: i64 = 32
34const FX_BASE10: i64 = 10
35const FX_EXIT_USAGE: i64 = 2
36const FX_EXIT_REFUSED: i64 = 4
37
38// ---- output ----
39func fx_puts(s: *u8) -> i64 {
40 var n: i64 = 0
41 while s[n] != (0 as u8) { n = n + 1 }
42 return sys_write(FX_OUT, s, n)
43}
44func fx_putn(n: i64) -> i64 {
45 if n == 0 { return sys_write(FX_OUT, "0" as *u8, 1) }
46 var x: i64 = n
47 var neg: i64 = 0
48 if n < 0 { neg = 1; x = 0 - n }
49 let tmp: *u8 = sts_mm(FX_TMPCAP)
50 var t: i64 = 0
51 while x > 0 { tmp[t] = (FX_D0 + (x % FX_BASE10)) as u8; t = t + 1; x = x / FX_BASE10 }
52 let out: *u8 = sts_mm(FX_NUMCAP)
53 var i: i64 = 0
54 if neg == 1 { out[0] = FX_MINUS as u8; i = 1 }
55 var k: i64 = t - 1
56 while k >= 0 { out[i] = tmp[k]; i = i + 1; k = k - 1 }
57 return sys_write(FX_OUT, out, i)
58}
59func fx_kv(k: *u8, v: i64) -> i64 {
60 fx_puts(k)
61 fx_puts("=" as *u8)
62 fx_putn(v)
63 fx_puts("\n" as *u8)
64 return 0
65}
66func fx_putslice(b: *u8, a: i64, e: i64) -> i64 {
67 let base: i64 = b as i64
68 return sys_write(FX_OUT, (base + a) as *u8, e - a)
69}
70
71// ---- buffered detail (contract rule 1: verdict first, detail last) ----
72func fx_bcat(b: *u8, o: i64, s: *u8) -> i64 {
73 var i: i64 = 0
74 var oo: i64 = o
75 while s[i] != (0 as u8) { b[oo] = s[i]; oo = oo + 1; i = i + 1 }
76 return oo
77}
78func fx_bcatn(b: *u8, o: i64, n: i64) -> i64 {
79 var oo: i64 = o
80 if n == 0 { b[oo] = FX_D0 as u8; return oo + 1 }
81 var x: i64 = n
82 if n < 0 { b[oo] = FX_MINUS as u8; oo = oo + 1; x = 0 - n }
83 let tmp: *u8 = sts_mm(FX_TMPCAP)
84 var t: i64 = 0
85 while x > 0 { tmp[t] = (FX_D0 + (x % FX_BASE10)) as u8; t = t + 1; x = x / FX_BASE10 }
86 var k: i64 = t - 1
87 while k >= 0 { b[oo] = tmp[k]; oo = oo + 1; k = k - 1 }
88 return oo
89}
90func fx_bcatsl(b: *u8, o: i64, src: *u8, a: i64, e: i64) -> i64 {
91 var oo: i64 = o
92 var i: i64 = a
93 while i < e { b[oo] = src[i]; oo = oo + 1; i = i + 1 }
94 return oo
95}
96
97// ---- parsing ----
98func fx_atoi(s: *u8) -> i64 {
99 var i: i64 = 0
100 var neg: i64 = 0
101 if s[0] == (FX_MINUS as u8) { neg = 1; i = 1 }
102 var v: i64 = 0
103 var go: i64 = 1
104 while go == 1 {
105 let c: i64 = s[i] as i64
106 if c < FX_D0 { go = 0 }
107 if c > FX_D9 { go = 0 }
108 if go == 1 { v = v * FX_BASE10 + (c - FX_D0); i = i + 1 }
109 }
110 if neg == 1 { return 0 - v }
111 return v
112}
113// END of the line starting at `i` in b[0..n) -- the scan idiom that was copy-pasted everywhere
114func fx_line_end(b: *u8, n: i64, i: i64) -> i64 {
115 var le: i64 = i
116 var s: i64 = 1
117 while s == 1 {
118 if le >= n { s = 0 } else { if b[le] == (FX_NL as u8) { s = 0 } else { le = le + 1 } }
119 }
120 return le
121}
122func fx_col(b: *u8, ls: i64, le: i64, idx: i64, out: *i64) -> i64 {
123 var c: i64 = 0
124 var p: i64 = ls
125 var found: i64 = 0
126 var go: i64 = 1
127 while go == 1 {
128 var e: i64 = p
129 var s: i64 = 1
130 while s == 1 {
131 if e >= le { s = 0 } else { if b[e] == (FX_TAB as u8) { s = 0 } else { e = e + 1 } }
132 }
133 if c == idx { out[0] = p; out[1] = e; found = 1; go = 0 }
134 if go == 1 {
135 if e >= le { go = 0 } else { p = e + 1; c = c + 1 }
136 }
137 }
138 return found
139}
140func fx_slice_atoi(b: *u8, a: i64, e: i64) -> i64 {
141 var v: i64 = 0
142 var neg: i64 = 0
143 var i: i64 = a
144 if i < e { if b[i] == (FX_MINUS as u8) { neg = 1; i = i + 1 } }
145 var go: i64 = 1
146 while i < e {
147 if go == 1 {
148 let c: i64 = b[i] as i64
149 if c >= FX_D0 {
150 if c <= FX_D9 { v = v * FX_BASE10 + (c - FX_D0) } else { go = 0 }
151 } else { go = 0 }
152 }
153 i = i + 1
154 }
155 if neg == 1 { return 0 - v }
156 return v
157}
158func fx_col_atoi(b: *u8, ls: i64, le: i64, idx: i64, sp: *i64) -> i64 {
159 if fx_col(b, ls, le, idx, sp) == 0 { return 0 }
160 return fx_slice_atoi(b, sp[0], sp[1])
161}
162func fx_slice_eqs(b: *u8, a: i64, e: i64, s: *u8) -> i64 {
163 var n: i64 = 0
164 while s[n] != (0 as u8) { n = n + 1 }
165 if e - a != n { return 0 }
166 var i: i64 = 0
167 while i < n { if b[a+i] != s[i] { return 0 } i = i + 1 }
168 return 1
169}
170func fx_slice_eq(a: *u8, a0: i64, a1: i64, b: *u8, b0: i64, b1: i64) -> i64 {
171 let n: i64 = a1 - a0
172 if b1 - b0 != n { return 0 }
173 var i: i64 = 0
174 while i < n { if a[a0+i] != b[b0+i] { return 0 } i = i + 1 }
175 return 1
176}
177
178// ---- plane row lookup ----
179func fx_row_by_id(b: *u8, n: i64, key: *u8, out: *i64, sp: *i64) -> i64 {
180 var i: i64 = 0
181 var found: i64 = 0
182 while i < n {
183 let le: i64 = fx_line_end(b, n, i)
184 if le > i { if found == 0 {
185 if fx_col(b, i, le, 0, sp) == 1 {
186 if fx_slice_eqs(b, sp[0], sp[1], key) == 1 { out[0] = i; out[1] = le; found = 1 }
187 }
188 } }
189 i = le + 1
190 }
191 return found
192}
193func fx_row_by_slice(b: *u8, n: i64, kb: *u8, k0: i64, k1: i64, out: *i64, sp: *i64) -> i64 {
194 var i: i64 = 0
195 var found: i64 = 0
196 while i < n {
197 let le: i64 = fx_line_end(b, n, i)
198 if le > i { if found == 0 {
199 if fx_col(b, i, le, 0, sp) == 1 {
200 if fx_slice_eq(b, sp[0], sp[1], kb, k0, k1) == 1 { out[0] = i; out[1] = le; found = 1 }
201 }
202 } }
203 i = le + 1
204 }
205 return found
206}
207// COVERAGE (contract rule 2): does a finding exist for (deal, component)? Someone who never LOOKED at
208// a mandatory system must not be scored as if that system were fine.
209func fx_has_finding(bf: *u8, nf: i64, deal: *u8, dealcol: i64, compcol: i64, kb: *u8, k0: i64, k1: i64, sp: *i64) -> i64 {
210 var i: i64 = 0
211 var found: i64 = 0
212 while i < nf {
213 let le: i64 = fx_line_end(bf, nf, i)
214 if le > i { if found == 0 {
215 if fx_col(bf, i, le, dealcol, sp) == 1 {
216 if fx_slice_eqs(bf, sp[0], sp[1], deal) == 1 {
217 if fx_col(bf, i, le, compcol, sp) == 1 {
218 if fx_slice_eq(bf, sp[0], sp[1], kb, k0, k1) == 1 { found = 1 }
219 }
220 }
221 }
222 } }
223 i = le + 1
224 }
225 return found
226}
227
228// ---- plane prefix composition (rule #17: the prefix root is a PARAMETER, never baked) ----
229func fx_cat2(root: *u8, tail: *u8) -> *u8 {
230 let out: *u8 = sts_mm(FX_PFXCAP)
231 var o: i64 = 0
232 var i: i64 = 0
233 while root[i] != (0 as u8) { out[o] = root[i]; o = o + 1; i = i + 1 }
234 i = 0
235 while tail[i] != (0 as u8) { out[o] = tail[i]; o = o + 1; i = i + 1 }
236 out[o] = 0 as u8
237 return out
238}
239// load a plane into a fresh buffer; nout[0] = bytes. Returns the buffer.
240func fx_plane(root: *u8, tail: *u8, nout: *i64) -> *u8 {
241 let b: *u8 = sts_mm(FX_BUF)
242 nout[0] = sts_load(fx_cat2(root, tail), b, FX_BUF)
243 return b
244}