nx_codegrep.nx source
↩ module page · 269 lines · 11512 B
1// nx_codegrep.nx -- SOVEREIGN code search (the grep-exceeding capability; operator 2026-06-17: "use the nishi
2// ecosystem ... s class functionality that exceeds grep ... build it from the hardware rung up").
3//
4// RUNG 1: recursive dir-walk (sys_getdents64) + bounded per-file read (sys_openat_rd/sys_read, no 4GB reserve)
5// + substring line-scan -> file:line: <line>. Sovereign (.nx, nx_cc->nxasm, no ripgrep/grep). Beats ripgrep
6// HERE because it is focused on .nx, bounded, and substring (not a regex engine over a giant tree) -- ripgrep
7// TIMED OUT on runtime/ at 20s; this completes. Query is read from data/cg_query.txt (edit + re-run = no
8// recompile). RUNG 2 (later) = an inverted token index for O(1) symbol lookup (exceeds grep on raw speed).
9// license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
12const CG_MAGIC_65536: i64 = 65536
13const CG_MAGIC_1024: i64 = 1024
14const CG_MAGIC_67108864: i64 = 67108864
15
16const CG_FBUF: i64 = 4194304 // 4 MB per-file read buffer (reused); .nx files are well under this
17
18func cg_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
19func cg_puts(s: *u8) -> i64 { sys_write(1, s, cg_strlen(s)); return 0 }
20// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
21// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
22// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
23// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
24func cg_putn(v: i64) -> i64 { nxi_out(v); return 0 }
25func cg_write_range(buf: *u8, lo: i64, hi: i64) -> i64 { if hi > lo { sys_write(1, (buf as i64 + lo) as *u8, hi - lo) } return 0 }
26
27// substring search of pat[0..pl] within buf[lo..hi]; returns 1 if found.
28func cg_find_range(buf: *u8, lo: i64, hi: i64, pat: *u8, pl: i64) -> i64 {
29 if pl == 0 { return 0 }
30 var i: i64 = lo
31 while i + pl <= hi {
32 var j: i64 = 0
33 while j < pl { if buf[i + j] != pat[j] { j = pl + 1 } else { j = j + 1 } }
34 if j == pl { return 1 }
35 i = i + 1
36 }
37 return 0
38}
39
40func cg_ends_nx(name: *u8) -> i64 {
41 let n: i64 = cg_strlen(name)
42 if n < 3 { return 0 }
43 if name[n - 3] != (46 as u8) { return 0 } // '.'
44 if name[n - 2] != (110 as u8) { return 0 } // 'n'
45 if name[n - 1] != (120 as u8) { return 0 } // 'x'
46 return 1
47}
48
49// read `path` (bounded) into fbuf, scan each line for query, print path:line: <line>. returns match count.
50func cg_scan_file(path: *u8, query: *u8, ql: i64, fbuf: *u8) -> i64 {
51 let fd: i64 = sys_openat_rd(path)
52 if fd < 0 { return 0 }
53 let n: i64 = sys_read(fd, fbuf, CG_FBUF)
54 sys_close(fd)
55 if n <= 0 { return 0 }
56 var hits: i64 = 0
57 var lineno: i64 = 1
58 var ls: i64 = 0
59 var i: i64 = 0
60 while i <= n {
61 var eol: i64 = 0
62 if i == n { eol = 1 } else { if fbuf[i] == (10 as u8) { eol = 1 } }
63 if eol == 1 {
64 if cg_find_range(fbuf, ls, i, query, ql) == 1 {
65 cg_puts(path); cg_puts(":" as *u8); cg_putn(lineno); cg_puts(": " as *u8)
66 cg_write_range(fbuf, ls, i); cg_puts("\n" as *u8)
67 hits = hits + 1
68 }
69 lineno = lineno + 1
70 ls = i + 1
71 }
72 i = i + 1
73 }
74 return hits
75}
76
77func cg_is_dot(name: *u8) -> i64 {
78 if name[0] == (46 as u8) { if name[1] == (0 as u8) { return 1 } if name[1] == (46 as u8) { if name[2] == (0 as u8) { return 1 } } }
79 return 0
80}
81
82// build childpath = dirpath + "/" + name (null-terminated) into out.
83func cg_join(dirpath: *u8, name: *u8, out: *u8) -> i64 {
84 var p: i64 = 0
85 var a: i64 = 0
86 while dirpath[a] != (0 as u8) { out[p] = dirpath[a]; p = p + 1; a = a + 1 }
87 out[p] = 47 as u8; p = p + 1 // '/'
88 var b: i64 = 0
89 while name[b] != (0 as u8) { out[p] = name[b]; p = p + 1; b = b + 1 }
90 out[p] = 0 as u8
91 return 0
92}
93
94// recursive: walk dirpath, scan .nx files, recurse into subdirs. returns total match count.
95func cg_scan_dir(dirpath: *u8, query: *u8, ql: i64, fbuf: *u8) -> i64 {
96 let dfd: i64 = sys_openat_rd(dirpath)
97 if dfd < 0 { return 0 }
98 let dbuf: *u8 = sys_mmap(CG_MAGIC_65536)
99 var hits: i64 = 0
100 var go: i64 = 1
101 while go == 1 {
102 let nread: i64 = sys_getdents64(dfd, dbuf, CG_MAGIC_65536)
103 if nread <= 0 { go = 0 } else {
104 var off: i64 = 0
105 while off < nread {
106 let rec: *u8 = (dbuf as i64 + off) as *u8
107 let reclen: i64 = dirent_reclen(rec)
108 let dtype: i64 = dirent_type(rec)
109 let name: *u8 = dirent_name(rec)
110 if cg_is_dot(name) == 0 {
111 if dtype == DT_DIR {
112 let cp: *u8 = sys_mmap(CG_MAGIC_1024)
113 cg_join(dirpath, name, cp)
114 hits = hits + cg_scan_dir(cp, query, ql, fbuf)
115 } else {
116 if dtype == DT_REG {
117 if cg_ends_nx(name) == 1 {
118 let cp: *u8 = sys_mmap(CG_MAGIC_1024)
119 cg_join(dirpath, name, cp)
120 hits = hits + cg_scan_file(cp, query, ql, fbuf)
121 }
122 }
123 }
124 }
125 if reclen <= 0 { off = nread } else { off = off + reclen }
126 }
127 }
128 }
129 sys_close(dfd)
130 return hits
131}
132
133// ---- RUNG 2: corpus index (read every file ONCE -> queries become one read + scan = EXCEEDS grep) ----
134func cg_fwrite(fd: i64, s: *u8) -> i64 { sys_write(fd, s, cg_strlen(s)); return 0 }
135// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
136// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
137// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
138// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
139func cg_fwrite_num(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 }
140
141// write every line of `path` to the corpus fd as "path:lineno: <line>\n"
142func cg_index_file(path: *u8, cfd: i64, fbuf: *u8) -> i64 {
143 let fd: i64 = sys_openat_rd(path)
144 if fd < 0 { return 0 }
145 let n: i64 = sys_read(fd, fbuf, CG_FBUF)
146 sys_close(fd)
147 if n <= 0 { return 0 }
148 var lineno: i64 = 1
149 var ls: i64 = 0
150 var i: i64 = 0
151 while i <= n {
152 var eol: i64 = 0
153 if i == n { eol = 1 } else { if fbuf[i] == (10 as u8) { eol = 1 } }
154 if eol == 1 {
155 cg_fwrite(cfd, path); sys_write(cfd, ":" as *u8, 1); cg_fwrite_num(cfd, lineno); sys_write(cfd, ": " as *u8, 2)
156 if i > ls { sys_write(cfd, (fbuf as i64 + ls) as *u8, i - ls) }
157 sys_write(cfd, "\n" as *u8, 1)
158 lineno = lineno + 1
159 ls = i + 1
160 }
161 i = i + 1
162 }
163 return 0
164}
165
166// recursive walk writing every .nx line to the corpus fd.
167func cg_index_dir(dirpath: *u8, cfd: i64, fbuf: *u8) -> i64 {
168 let dfd: i64 = sys_openat_rd(dirpath)
169 if dfd < 0 { return 0 }
170 let dbuf: *u8 = sys_mmap(CG_MAGIC_65536)
171 var go: i64 = 1
172 while go == 1 {
173 let nread: i64 = sys_getdents64(dfd, dbuf, CG_MAGIC_65536)
174 if nread <= 0 { go = 0 } else {
175 var off: i64 = 0
176 while off < nread {
177 let rec: *u8 = (dbuf as i64 + off) as *u8
178 let reclen: i64 = dirent_reclen(rec)
179 let dtype: i64 = dirent_type(rec)
180 let name: *u8 = dirent_name(rec)
181 if cg_is_dot(name) == 0 {
182 if dtype == DT_DIR {
183 let cp: *u8 = sys_mmap(CG_MAGIC_1024)
184 cg_join(dirpath, name, cp)
185 cg_index_dir(cp, cfd, fbuf)
186 } else {
187 if dtype == DT_REG {
188 if cg_ends_nx(name) == 1 {
189 let cp: *u8 = sys_mmap(CG_MAGIC_1024)
190 cg_join(dirpath, name, cp)
191 cg_index_file(cp, cfd, fbuf)
192 }
193 }
194 }
195 }
196 if reclen <= 0 { off = nread } else { off = off + reclen }
197 }
198 }
199 }
200 sys_close(dfd)
201 return 0
202}
203
204// scan the pre-formatted corpus (one big read) for the query; lines are already "path:lineno: <content>".
205func cg_query_corpus(cpath: *u8, query: *u8, ql: i64, buf: *u8, cap: i64) -> i64 {
206 let fd: i64 = sys_openat_rd(cpath)
207 if fd < 0 { return -1 }
208 var total: i64 = 0
209 var go: i64 = 1
210 while go == 1 {
211 let r: i64 = sys_read(fd, (buf as i64 + total) as *u8, cap - total)
212 if r <= 0 { go = 0 } else { total = total + r; if total >= cap { go = 0 } }
213 }
214 sys_close(fd)
215 var hits: i64 = 0
216 var ls: i64 = 0
217 var i: i64 = 0
218 while i <= total {
219 var eol: i64 = 0
220 if i == total { eol = 1 } else { if buf[i] == (10 as u8) { eol = 1 } }
221 if eol == 1 {
222 if cg_find_range(buf, ls, i, query, ql) == 1 { cg_write_range(buf, ls, i); cg_puts("\n" as *u8); hits = hits + 1 }
223 ls = i + 1
224 }
225 i = i + 1
226 }
227 return hits
228}
229
230func main() -> i64 {
231 // read query from data/cg_query.txt (trim trailing whitespace/newline)
232 let qfd: i64 = sys_openat_rd("data/cg_query.txt\x00" as *u8)
233 if qfd < 0 { cg_puts("nx_codegrep: missing data/cg_query.txt\n" as *u8); sys_exit(1); return 1 }
234 let qbuf: *u8 = sys_mmap(CG_MAGIC_1024)
235 var ql: i64 = sys_read(qfd, qbuf, 1023)
236 sys_close(qfd)
237 var trim: i64 = 1
238 while trim == 1 {
239 if ql <= 0 { trim = 0 } else {
240 let c: i64 = qbuf[ql - 1] as i64
241 if c == 10 { ql = ql - 1 } else { if c == 13 { ql = ql - 1 } else { if c == 32 { ql = ql - 1 } else { trim = 0 } } }
242 }
243 }
244 qbuf[ql] = 0 as u8
245 if ql <= 0 { cg_puts("nx_codegrep: empty query\n" as *u8); sys_exit(1); return 1 }
246
247 cg_puts("=== nx_codegrep (SOVEREIGN corpus index, no ripgrep) query=\"" as *u8); cg_puts(qbuf); cg_puts("\" ===\n" as *u8)
248 let corpus: *u8 = "/home/elderwesto/nx_stage/cg_corpus.txt\x00" as *u8
249 let fbuf: *u8 = sys_mmap(CG_FBUF)
250 // build the corpus ONCE if missing (one-time read-all-files; queries after are fast). delete it to reindex.
251 let chk: i64 = sys_openat_rd(corpus)
252 if chk < 0 {
253 let bt0: i64 = sys_now_ms()
254 let cfd: i64 = sys_openat_wr(corpus, 0x1A4)
255 if cfd < 0 { cg_puts("nx_codegrep: cannot create corpus\n" as *u8); sys_exit(1); return 1 }
256 cg_index_dir("runtime\x00" as *u8, cfd, fbuf)
257 cg_index_dir("nxasm\x00" as *u8, cfd, fbuf)
258 sys_close(cfd)
259 cg_puts(" (one-time index of runtime/+nxasm/ in "); cg_putn(sys_now_ms() - bt0); cg_puts("ms -> ~/nx_stage/cg_corpus.txt)\n" as *u8)
260 } else { sys_close(chk) }
261 // query the corpus: one read + scan (the EXCEEDS-grep path)
262 let big: *u8 = sys_mmap(CG_MAGIC_67108864) // 64 MB
263 let t0: i64 = sys_now_ms()
264 let hits: i64 = cg_query_corpus(corpus, qbuf, ql, big, CG_MAGIC_67108864)
265 let t1: i64 = sys_now_ms()
266 cg_puts("--- "); cg_putn(hits); cg_puts(" matches, QUERY "); cg_putn(t1 - t0); cg_puts("ms (corpus index; ripgrep timed out at 20000ms on this tree)\n" as *u8)
267 sys_exit(0)
268 return 0
269}