nx_underbuilt_lib.nx source
↩ module page · 249 lines · 8365 B
1// nx_underbuilt_lib.nx -- R6 parse/tally core for the NHTSA underbuilt-part signal (LIB, no main; imported
2// by nx_underbuilt_board + nx_underbuilt_gate). Context-byte JSON key matching (quote-key-quote-colon) so no
3// quote characters appear in nx string literals; component values split on commas and tallied in a ctx-table
4// arena. ctx t: *i64 slots: 0=name-arena ptr, 1=arena-used, 2=off[] ptr, 3=len[] ptr, 4=count[] ptr,
5// 5=ndistinct, 6=records (key occurrences), 7=tokens (sum of counts), 8=arena cap.
6// Board persistence to seg_store = a later rung; v0 board is printed + gated. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8
9func ubl_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
10func ubl_putn(v: i64) -> i64 {
11 let bb: *u8 = sys_mmap(28)
12 var m: i64 = v
13 if m < 0 { ubl_puts("-" as *u8); m = 0 - m }
14 let t: *u8 = sys_mmap(28)
15 var k: i64 = 0
16 if m == 0 { t[0] = 48 as u8; k = 1 }
17 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
18 var i: i64 = 0
19 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
20 sys_write(1, bb, k)
21 return 0
22}
23
24// read whole file into buf (cap-bounded); returns bytes or -1
25func ubl_read(path: *u8, buf: *u8, cap: i64) -> i64 {
26 let fd: i64 = sys_openat_rd(path)
27 if fd < 0 { return 0 - 1 }
28 var off: i64 = 0
29 var going: i64 = 1
30 while going == 1 {
31 if off >= cap { going = 0 } else {
32 let want: i64 = cap - off
33 let p: *u8 = ((buf as i64) + off) as *u8
34 let r: i64 = sys_read(fd, p, want)
35 if r <= 0 { going = 0 } else { off = off + r }
36 }
37 }
38 sys_close(fd)
39 return off
40}
41
42// 1 if key bytes match at 'at' with JSON context: quote before, quote+colon after
43func ubl_match(buf: *u8, n: i64, key: *u8, klen: i64, at: i64) -> i64 {
44 if at < 1 { return 0 }
45 if at + klen + 2 > n { return 0 }
46 var j: i64 = 0
47 while j < klen {
48 if buf[at + j] != key[j] { return 0 }
49 j = j + 1
50 }
51 if buf[at - 1] != (34 as u8) { return 0 }
52 if buf[at + klen] != (34 as u8) { return 0 }
53 if buf[at + klen + 1] != (58 as u8) { return 0 }
54 return 1
55}
56
57// next context-verified key occurrence at/after 'from'; -1 if none
58func ubl_next(buf: *u8, n: i64, key: *u8, klen: i64, from: i64) -> i64 {
59 var i: i64 = from
60 if i < 1 { i = 1 }
61 let k0: u8 = key[0]
62 while i + klen + 2 <= n {
63 if buf[i] == k0 {
64 let m: i64 = ubl_match(buf, n, key, klen, i)
65 if m == 1 { return i }
66 }
67 i = i + 1
68 }
69 return 0 - 1
70}
71
72// first integer value of key (skips spaces; digits only); -1 if absent
73func ubl_key_int(buf: *u8, n: i64, key: *u8, klen: i64) -> i64 {
74 let i: i64 = ubl_next(buf, n, key, klen, 0)
75 if i < 0 { return 0 - 1 }
76 var v: i64 = i + klen + 2
77 var sk: i64 = 1
78 while sk == 1 {
79 if v < n { if buf[v] == (32 as u8) { v = v + 1 } else { sk = 0 } } else { sk = 0 }
80 }
81 var val: i64 = 0
82 var got: i64 = 0
83 var going: i64 = 1
84 while going == 1 {
85 if v >= n { going = 0 } else {
86 let c: i64 = buf[v] as i64
87 if c >= 48 {
88 if c <= 57 { val = val * 10 + (c - 48); got = 1; v = v + 1 } else { going = 0 }
89 } else { going = 0 }
90 }
91 }
92 if got == 0 { return 0 - 1 }
93 return val
94}
95
96// count key occurrences whose value starts with 't' (true)
97func ubl_count_true(buf: *u8, n: i64, key: *u8, klen: i64) -> i64 {
98 var total: i64 = 0
99 var i: i64 = ubl_next(buf, n, key, klen, 0)
100 while i >= 0 {
101 var v: i64 = i + klen + 2
102 var sk: i64 = 1
103 while sk == 1 {
104 if v < n { if buf[v] == (32 as u8) { v = v + 1 } else { sk = 0 } } else { sk = 0 }
105 }
106 if v < n { if buf[v] == (116 as u8) { total = total + 1 } }
107 i = ubl_next(buf, n, key, klen, v)
108 }
109 return total
110}
111
112func ubl_reset(t: *i64) -> i64 { t[1] = 0; t[5] = 0; t[6] = 0; t[7] = 0; return 0 }
113
114// find-or-add token [at,at+len) from buf into the tally; count++
115func ubl_tok_add(t: *i64, buf: *u8, at: i64, len: i64) -> i64 {
116 let arena: *u8 = t[0] as *u8
117 let offs: *i64 = t[2] as *i64
118 let lens: *i64 = t[3] as *i64
119 let cnts: *i64 = t[4] as *i64
120 var found: i64 = 0 - 1
121 var k: i64 = 0
122 while k < t[5] {
123 if found < 0 {
124 if lens[k] == len {
125 let ao: i64 = offs[k]
126 var same: i64 = 1
127 var j: i64 = 0
128 while j < len {
129 if arena[ao + j] != buf[at + j] { same = 0; j = len } else { j = j + 1 }
130 }
131 if same == 1 { found = k }
132 }
133 }
134 k = k + 1
135 }
136 if found >= 0 {
137 cnts[found] = cnts[found] + 1
138 t[7] = t[7] + 1
139 return found
140 }
141 if t[5] >= 512 { return 0 - 1 }
142 if t[1] + len > t[8] { return 0 - 1 }
143 let nd: i64 = t[5]
144 offs[nd] = t[1]
145 lens[nd] = len
146 cnts[nd] = 1
147 var j2: i64 = 0
148 while j2 < len { arena[t[1] + j2] = buf[at + j2]; j2 = j2 + 1 }
149 t[1] = t[1] + len
150 t[5] = nd + 1
151 t[7] = t[7] + 1
152 return nd
153}
154
155// tally every string value of key: records++ per occurrence, split value on commas, trim spaces, add tokens
156func ubl_tally(t: *i64, buf: *u8, n: i64, key: *u8, klen: i64) -> i64 {
157 var i: i64 = ubl_next(buf, n, key, klen, 0)
158 while i >= 0 {
159 var v: i64 = i + klen + 2
160 var sk: i64 = 1
161 while sk == 1 {
162 if v < n { if buf[v] == (32 as u8) { v = v + 1 } else { sk = 0 } } else { sk = 0 }
163 }
164 var resume: i64 = v
165 if v < n {
166 if buf[v] == (34 as u8) {
167 var e: i64 = v + 1
168 var sc: i64 = 1
169 while sc == 1 {
170 if e < n { if buf[e] == (34 as u8) { sc = 0 } else { e = e + 1 } } else { sc = 0 }
171 }
172 t[6] = t[6] + 1
173 var ts: i64 = v + 1
174 var p: i64 = v + 1
175 while p <= e {
176 var isend: i64 = 0
177 if p == e { isend = 1 } else { if buf[p] == (44 as u8) { isend = 1 } }
178 if isend == 1 {
179 var a: i64 = ts
180 var b: i64 = p
181 var tr: i64 = 1
182 while tr == 1 {
183 if a < b { if buf[a] == (32 as u8) { a = a + 1 } else { tr = 0 } } else { tr = 0 }
184 }
185 tr = 1
186 while tr == 1 {
187 if b > a { if buf[b - 1] == (32 as u8) { b = b - 1 } else { tr = 0 } } else { tr = 0 }
188 }
189 if b > a { let dummy: i64 = ubl_tok_add(t, buf, a, b - a) }
190 ts = p + 1
191 }
192 p = p + 1
193 }
194 resume = e + 1
195 }
196 }
197 i = ubl_next(buf, n, key, klen, resume)
198 }
199 return t[6]
200}
201
202// fill rank[0..m) with distinct-token indices sorted by count desc; returns m
203func ubl_top(t: *i64, rank: *i64, kmax: i64) -> i64 {
204 let cnts: *i64 = t[4] as *i64
205 var m: i64 = kmax
206 if t[5] < m { m = t[5] }
207 var r: i64 = 0
208 while r < m {
209 var best: i64 = 0 - 1
210 var bestc: i64 = 0 - 1
211 var k: i64 = 0
212 while k < t[5] {
213 var used: i64 = 0
214 var q: i64 = 0
215 while q < r { if rank[q] == k { used = 1 } q = q + 1 }
216 if used == 0 { if cnts[k] > bestc { bestc = cnts[k]; best = k } }
217 k = k + 1
218 }
219 rank[r] = best
220 r = r + 1
221 }
222 return m
223}
224
225// print token name idx
226func ubl_name_out(t: *i64, idx: i64) -> i64 {
227 let offs: *i64 = t[2] as *i64
228 let lens: *i64 = t[3] as *i64
229 let p: *u8 = (t[0] + offs[idx]) as *u8
230 sys_write(1, p, lens[idx])
231 return 0
232}
233
234// 1 if token idx equals zero-terminated s
235func ubl_name_is(t: *i64, idx: i64, s: *u8) -> i64 {
236 let offs: *i64 = t[2] as *i64
237 let lens: *i64 = t[3] as *i64
238 var sl: i64 = 0
239 while s[sl] != (0 as u8) { sl = sl + 1 }
240 if lens[idx] != sl { return 0 }
241 let arena: *u8 = t[0] as *u8
242 let ao: i64 = offs[idx]
243 var j: i64 = 0
244 while j < sl {
245 if arena[ao + j] != s[j] { return 0 }
246 j = j + 1
247 }
248 return 1
249}