nx_mhtarget_lib.nx source
↩ module page · 224 lines · 8469 B
1// nx_mhtarget_lib.nx -- MAKEHUMAN TARGET FACT EXTRACTION CORE (the CC0 morph-target dialect;
2// /compare/koikatsu card-class lane, admitted 2026-08-30). A MakeHuman .target is a text file:
3// comment lines starting with a hash byte, blank lines, and DATA rows of exactly four
4// whitespace-separated tokens -- vertex index (uint) then dx dy dz as signed decimals which may
5// carry a LEADING DOT (measured on the real corpus 2026-08-30: 1675 rows, 4 fields each, max 3
6// fractional digits, 637 negatives, no exponents, max index 18001).
7// SCHEMA GROUND TRUTH is the fetched real corpus itself (makehumancommunity/makehuman, assets CC0
8// per LICENSE.ASSETS.md and each file's own header) -- the licence-clean control oracle beside the
9// per-author BodySlide/Nexus lane. Offsets decode to MICRO units (value x 1000000, integer, sign
10// carried, up to six fractional digits kept, extras declared truncated -- numbers, not verdicts).
11// Byte access composes kk_b from the sibling dialect lib; line walking is this dialect's own, and
12// every scan is a BOUNDED FLAG LOOP -- a loop-exit sentinel written into the cursor erases the
13// answer (standing law; the first draft of this very file committed it and was rewritten).
14// Slots: [0] is_target [1] data_rows [2] comment_rows [3] blank_rows [4] max_vert_index
15// [5] bad_rows [6..9] reserved -1
16// license_tier: ORIGINAL No hw writes (Rule 26).
17import "nx_syscalls.nx"
18import "nx_kkfacts_lib.nx"
19
20const MHT_N_SLOTS: i64 = 10
21const MHT_MICRO: i64 = 1000000
22const MHT_FRAC_KEEP: i64 = 6 // fractional digits kept; beyond this consumed but truncated (declared)
23const MHT_BAD: i64 = 0 - 1000000000000 // impossible offset (-1e6 model units); decode stops on it
24const MHT_CH_HASH: i64 = 35
25const MHT_CH_NL: i64 = 10
26const MHT_CH_CR: i64 = 13
27const MHT_CH_SP: i64 = 32
28const MHT_CH_TAB: i64 = 9
29const MHT_CH_MINUS: i64 = 45
30const MHT_CH_DOT: i64 = 46
31const MHT_CH_0: i64 = 48
32const MHT_CH_9: i64 = 57
33
34// row classification codes
35const MHT_ROW_COMMENT: i64 = 0
36const MHT_ROW_BLANK: i64 = 1
37const MHT_ROW_DATA: i64 = 2
38const MHT_ROW_BAD: i64 = 3
39
40func mht_is_ws(c: i64) -> i64 { if c == MHT_CH_SP { return 1 } if c == MHT_CH_TAB { return 1 } if c == MHT_CH_CR { return 1 } return 0 }
41func mht_is_digit(c: i64) -> i64 { if c < MHT_CH_0 { return 0 } if c > MHT_CH_9 { return 0 } return 1 }
42
43// bounded whitespace skip: first non-ws position at or after p, never past le
44func mht_skip_ws(buf: *u8, p: i64, le: i64) -> i64 {
45 var q: i64 = p
46 var moving: i64 = 1
47 while moving == 1 {
48 if q >= le { moving = 0 } else {
49 if mht_is_ws(kk_b(buf, q)) == 1 { q = q + 1 } else { moving = 0 }
50 }
51 }
52 return q
53}
54// bounded token end: first ws position at or after p, never past le
55func mht_tok_end(buf: *u8, p: i64, le: i64) -> i64 {
56 var q: i64 = p
57 var moving: i64 = 1
58 while moving == 1 {
59 if q >= le { moving = 0 } else {
60 if mht_is_ws(kk_b(buf, q)) == 0 { q = q + 1 } else { moving = 0 }
61 }
62 }
63 return q
64}
65// bounded line end: position of the newline at or after ls, or end when none remains
66func mht_line_end(buf: *u8, ls: i64, end: i64) -> i64 {
67 var q: i64 = ls
68 var moving: i64 = 1
69 while moving == 1 {
70 if q >= end { moving = 0 } else {
71 if kk_b(buf, q) == MHT_CH_NL { moving = 0 } else { q = q + 1 }
72 }
73 }
74 return q
75}
76
77// parse an unsigned integer token; -1 on any non-digit or empty
78func mht_uint(buf: *u8, off: i64, len: i64) -> i64 {
79 if len <= 0 { return 0 - 1 }
80 var v: i64 = 0
81 var i: i64 = 0
82 while i < len {
83 let c: i64 = kk_b(buf, off + i)
84 if mht_is_digit(c) == 0 { return 0 - 1 }
85 v = v * 10 + (c - MHT_CH_0)
86 i = i + 1
87 }
88 return v
89}
90
91// parse a signed decimal token (leading dot allowed) to MICRO units; MHT_BAD on malformation.
92func mht_num_micro(buf: *u8, off: i64, len: i64) -> i64 {
93 if len <= 0 { return MHT_BAD }
94 var i: i64 = 0
95 var neg: i64 = 0
96 var whole: i64 = 0
97 var frac: i64 = 0
98 var place: i64 = MHT_MICRO / 10 // first fractional digit is worth 100000 micro
99 var dot: i64 = 0
100 var digits: i64 = 0
101 while i < len {
102 let c: i64 = kk_b(buf, off + i)
103 if c == MHT_CH_MINUS {
104 if i != 0 { return MHT_BAD }
105 neg = 1
106 } else { if c == MHT_CH_DOT {
107 if dot == 1 { return MHT_BAD }
108 dot = 1
109 } else { if mht_is_digit(c) == 0 { return MHT_BAD } else {
110 digits = digits + 1
111 if dot == 0 { whole = whole * 10 + (c - MHT_CH_0) }
112 if dot == 1 { if place > 0 { frac = frac + (c - MHT_CH_0) * place; place = place / 10 } }
113 } } }
114 i = i + 1
115 }
116 if digits == 0 { return MHT_BAD }
117 var v: i64 = whole * MHT_MICRO + frac
118 if neg == 1 { return 0 - v }
119 return v
120}
121
122// classify + parse ONE line [ls,le). On DATA writes out4[0]=vert_index, out4[1..3]=micro offsets.
123func mht_row(buf: *u8, ls: i64, le: i64, out4: *i64) -> i64 {
124 var p: i64 = mht_skip_ws(buf, ls, le)
125 if p >= le { return MHT_ROW_BLANK }
126 if kk_b(buf, p) == MHT_CH_HASH { return MHT_ROW_COMMENT }
127 var t: i64 = 0
128 while t < 4 {
129 p = mht_skip_ws(buf, p, le)
130 if p >= le { return MHT_ROW_BAD }
131 let e: i64 = mht_tok_end(buf, p, le)
132 if t == 0 {
133 let vi: i64 = mht_uint(buf, p, e - p)
134 if vi < 0 { return MHT_ROW_BAD }
135 out4[0] = vi
136 } else {
137 let mv: i64 = mht_num_micro(buf, p, e - p)
138 if mv == MHT_BAD { return MHT_ROW_BAD }
139 out4[t] = mv
140 }
141 p = e
142 t = t + 1
143 }
144 p = mht_skip_ws(buf, p, le)
145 if p < le { return MHT_ROW_BAD }
146 return MHT_ROW_DATA
147}
148
149// probe core: buf holds the first n bytes; file_size = true size. Census only over a COMPLETE
150// file; a truncated read decides is_target from the complete-line PREFIX and abstains (-1) from
151// every count -- a truncated count is an undercount.
152func mht_probe(buf: *u8, n: i64, file_size: i64, facts: *i64) -> i64 {
153 var i: i64 = 0
154 while i < MHT_N_SLOTS { facts[i] = 0 - 1; i = i + 1 }
155 facts[0] = 0
156 if n <= 0 { return 0 }
157 var complete: i64 = 0
158 if file_size <= n { complete = 1 }
159 var scan_end: i64 = n
160 if complete == 0 {
161 // retreat to the last complete line, boundedly
162 var q: i64 = n - 1
163 var found: i64 = 0 - 1
164 var moving: i64 = 1
165 while moving == 1 {
166 if q < 0 { moving = 0 } else {
167 if kk_b(buf, q) == MHT_CH_NL { found = q; moving = 0 } else { q = q - 1 }
168 }
169 }
170 if found < 0 { return 0 }
171 scan_end = found + 1
172 }
173 let out4: *i64 = sys_mmap(32) as *i64
174 var rows: i64 = 0
175 var comments: i64 = 0
176 var blanks: i64 = 0
177 var bad: i64 = 0
178 var maxv: i64 = 0 - 1
179 var ls: i64 = 0
180 while ls < scan_end {
181 let eol: i64 = mht_line_end(buf, ls, scan_end)
182 let cls: i64 = mht_row(buf, ls, eol, out4)
183 if cls == MHT_ROW_DATA { rows = rows + 1; if out4[0] > maxv { maxv = out4[0] } }
184 if cls == MHT_ROW_COMMENT { comments = comments + 1 }
185 if cls == MHT_ROW_BLANK { blanks = blanks + 1 }
186 if cls == MHT_ROW_BAD { bad = bad + 1 }
187 ls = eol + 1
188 }
189 if rows >= 1 { if bad == 0 { facts[0] = 1 } }
190 if complete == 1 {
191 facts[1] = rows
192 facts[2] = comments
193 facts[3] = blanks
194 facts[4] = maxv
195 facts[5] = bad
196 }
197 return 0
198}
199
200// decode all data rows, honest-partial: meta[0] = candidate rows encountered (non-comment,
201// non-blank); a BAD row STOPS the parse so parsed < declared is visible, never papered over.
202func mht_decode(buf: *u8, n: i64, idxs: *i64, dxs: *i64, dys: *i64, dzs: *i64, outcap: i64, meta: *i64) -> i64 {
203 meta[0] = 0
204 let out4: *i64 = sys_mmap(32) as *i64
205 var parsed: i64 = 0
206 var ls: i64 = 0
207 while ls < n {
208 let eol: i64 = mht_line_end(buf, ls, n)
209 let cls: i64 = mht_row(buf, ls, eol, out4)
210 if cls == MHT_ROW_BAD { meta[0] = meta[0] + 1; return parsed }
211 if cls == MHT_ROW_DATA {
212 meta[0] = meta[0] + 1
213 if parsed < outcap {
214 idxs[parsed] = out4[0]
215 dxs[parsed] = out4[1]
216 dys[parsed] = out4[2]
217 dzs[parsed] = out4[3]
218 }
219 parsed = parsed + 1
220 }
221 ls = eol + 1
222 }
223 return parsed
224}