nx_rowparse_lib.nx source
↩ module page · 141 lines · 5287 B
1// nx_rowparse_lib.nx -- THE ONE ROW PARSER for delimited estate records, extracted 2026-09-04 because the
2// DRY law fires at THREE and the third copy had just been written. nx_debt_triple parsed TAB-delimited debt
3// rows, nx_aliascensus parsed TAB-delimited allowlist rows, and nx_refdrift parsed PIPE-delimited refs rows,
4// each with its own private slen, line-end, column, span-compare and number-emit -- the same arithmetic
5// written three times with three prefixes. Each copy was CORRECT; that is precisely why the duplication was
6// invisible, and why the estate's rule is a COUNT rather than a judgement about whether it feels duplicated.
7//
8// THE SEPARATOR IS A PARAMETER, WHICH IS THE WHOLE REASON ONE LIB CAN SERVE ALL THREE. The three organs
9// differed on exactly one axis: TAB for the store planes, PIPE for the compare records. A lib that hardcoded
10// either would have forced the third organ to keep its private copy, which is how a shared lib acquires a
11// duplicate sibling and the count goes from three to four.
12//
13// ⚠A NOTE ON WHAT IS NOT HERE. Nothing in this file reads a file, forks, or decides anything. It is pure
14// span arithmetic over a caller-owned buffer, so a consumer's gate can exercise it with a hand-built fixture
15// and no I/O -- which is the property that made the three consumers gateable in the first place.
16// license_tier: ORIGINAL. No syscalls except the emit helpers' scratch allocation. No hw writes (Rule 26).
17import "nx_syscalls.nx"
18
19const RP_NL: i64 = 10
20const RP_TAB: i64 = 9
21const RP_PIPE: i64 = 124
22const RP_ZERO: i64 = 48
23const RP_NINE: i64 = 57
24const RP_MINUS: i64 = 45
25const RP_SCRATCH: i64 = 32
26const RP_TEN: i64 = 10
27
28func rp_slen(s: *u8) -> i64 {
29 var i: i64 = 0
30 while s[i] != (0 as u8) { i = i + 1 }
31 return i
32}
33// end of the line starting at i, or n. Never clobbers the caller's cursor: the caller advances past the
34// returned index itself, which is the loop-exit-by-cursor-clobber defect this estate has paid for four times.
35func rp_le(b: *u8, i: i64, n: i64) -> i64 {
36 var e: i64 = i
37 while e < n {
38 if b[e] == (RP_NL as u8) { return e }
39 e = e + 1
40 }
41 return n
42}
43// span of column `col` (0-based) in [s,e) delimited by `sep`; fills out[0]=start out[1]=len, returns 1.
44// A row with fewer columns returns 0 rather than an empty span, so a caller cannot mistake "absent" for
45// "present and empty" -- two states with different remedies.
46func rp_col(b: *u8, s: i64, e: i64, col: i64, sep: i64, out: *i64) -> i64 {
47 var k: i64 = 0
48 var p: i64 = s
49 var st: i64 = s
50 while p <= e {
51 var isend: i64 = 0
52 if p == e { isend = 1 }
53 if isend == 0 { if b[p] == (sep as u8) { isend = 1 } }
54 if isend == 1 {
55 if k == col { out[0] = st; out[1] = p - st; return 1 }
56 k = k + 1
57 st = p + 1
58 }
59 p = p + 1
60 }
61 return 0
62}
63func rp_col_tab(b: *u8, s: i64, e: i64, col: i64, out: *i64) -> i64 {
64 return rp_col(b, s, e, col, RP_TAB, out)
65}
66func rp_col_pipe(b: *u8, s: i64, e: i64, col: i64, out: *i64) -> i64 {
67 return rp_col(b, s, e, col, RP_PIPE, out)
68}
69func rp_span_eq(b: *u8, s: i64, l: i64, b2: *u8, s2: i64, l2: i64) -> i64 {
70 if l != l2 { return 0 }
71 var i: i64 = 0
72 while i < l {
73 if b[s+i] != b2[s2+i] { return 0 }
74 i = i + 1
75 }
76 return 1
77}
78func rp_lit_eq(b: *u8, s: i64, l: i64, lit: *u8) -> i64 {
79 let n: i64 = rp_slen(lit)
80 if l != n { return 0 }
81 var i: i64 = 0
82 while i < n {
83 if b[s+i] != lit[i] { return 0 }
84 i = i + 1
85 }
86 return 1
87}
88// leading decimal digits as an integer; stops at the first non-digit and returns what it had.
89func rp_num(b: *u8, s: i64, l: i64) -> i64 {
90 var v: i64 = 0
91 var i: i64 = 0
92 while i < l {
93 let c: i64 = b[s+i] as i64
94 if c < RP_ZERO { return v }
95 if c > RP_NINE { return v }
96 v = v * RP_TEN + (c - RP_ZERO)
97 i = i + 1
98 }
99 return v
100}
101// identical byte ranges? A LENGTH difference alone is a difference, which is the tooth that stops a
102// prefix-only comparator calling a truncated body identical.
103func rp_same(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
104 if an != bn { return 0 }
105 var i: i64 = 0
106 while i < an {
107 if a[i] != b[i] { return 0 }
108 i = i + 1
109 }
110 return 1
111}
112func rp_put(out: *u8, o: i64, s: *u8) -> i64 {
113 let n: i64 = rp_slen(s)
114 var i: i64 = 0
115 while i < n { out[o+i] = s[i]; i = i + 1 }
116 return o + n
117}
118func rp_putn(out: *u8, o: i64, v: i64) -> i64 {
119 if v == 0 { out[o] = RP_ZERO as u8; return o + 1 }
120 var x: i64 = v
121 var neg: i64 = 0
122 if x < 0 { neg = 1; x = 0 - x }
123 let t: *u8 = sys_mmap(RP_SCRATCH)
124 var k: i64 = 0
125 while x > 0 { t[k] = ((x - (x / RP_TEN) * RP_TEN) + RP_ZERO) as u8; x = x / RP_TEN; k = k + 1 }
126 var p: i64 = o
127 if neg == 1 { out[p] = RP_MINUS as u8; p = p + 1 }
128 while k > 0 { k = k - 1; out[p] = t[k]; p = p + 1 }
129 return p
130}
131func rp_putspan(out: *u8, o: i64, b: *u8, s: i64, l: i64) -> i64 {
132 var i: i64 = 0
133 while i < l { out[o+i] = b[s+i]; i = i + 1 }
134 return o + l
135}
136func rp_cstr(dst: *u8, b: *u8, s: i64, l: i64) -> i64 {
137 var i: i64 = 0
138 while i < l { dst[i] = b[s+i]; i = i + 1 }
139 dst[l] = 0 as u8
140 return l
141}