code wiki / (root) / nx_rowparse_lib.nx

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}