code wiki / _hdl_build / nx_eco_graph_build.nx

nx_eco_graph_build.nx source

↩ module page · 224 lines · 10886 B

1// nx_eco_graph_build.nx -- R0 brick-3: the LIVE whole-tree walk that POPULATES the ecosystem graph from real 2// organs, then answers the operator's query. Composes nx_dr_tree's getdents recursion + nx_import_scan (accurate 3// edges) + nx_eco_graph (queries). Usage: nx_eco_graph_build <root-dir> [query-basename] 4// no query -> summary (nodes, edges, files, top hub, orphan count) 5// query X.nx -> its ROOTS-TO-GOD (transitive imports/ancestors), CHILDREN (transitive importers), Ca/Ce. 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_eco_graph.nx" 9import "nx_import_scan.nx" 10const EGB_MAGIC_3900: i64 = 3900 11const EGB_MAGIC_131072: i64 = 131072 12const EGB_MAGIC_1024: i64 = 1024 13const EGB_MAGIC_4096: i64 = 4096 14 15const EGB_MAXNODE: i64 = 24000 16const EGB_MAXEDGE: i64 = 300000 17const EGB_ARENA: i64 = 4194304 18const EGB_HASH: i64 = 65536 19const EGB_FILECAP: i64 = 262144 20 21func bw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 22func bn(v: i64) -> i64 { let b: *u8=sys_mmap(24); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} let t: *u8=sys_mmap(24); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var j: i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 23func bslen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 24 25func egb_is_nx(nm: *u8, n: i64) -> i64 { 26 if n < 4 { return 0 } 27 if nm[n-3] != (46 as u8) { return 0 } 28 if nm[n-2] != (110 as u8) { return 0 } 29 if nm[n-1] != (120 as u8) { return 0 } 30 return 1 31} 32// append "/name" to path at base_n; return new length (NOT NUL-terminated here). 33func egb_join(path: *u8, base_n: i64, nm: *u8) -> i64 { 34 path[base_n] = 47 as u8 35 var o: i64 = base_n + 1 36 var i: i64 = 0 37 while nm[i] != (0 as u8) { path[o] = nm[i]; o = o + 1; i = i + 1 } 38 return o 39} 40func egb_read(path: *u8, buf: *u8, cap: i64) -> i64 { 41 let fd: i64 = sys_openat_rd(path) 42 if fd < 0 { return 0 } 43 var total: i64 = 0 44 var go: i64 = 1 45 while go == 1 { 46 let nr: i64 = sys_read(fd, ((buf as i64)+total) as *u8, cap - total) 47 if nr <= 0 { go = 0 } else { total = total + nr; if total >= cap { go = 0 } } 48 } 49 sys_close(fd) 50 return total 51} 52func egb_isdotdot(nm: *u8) -> i64 { 53 if nm[0] == (46 as u8) { if nm[1] == (0 as u8) { return 1 } if nm[1] == (46 as u8) { if nm[2] == (0 as u8) { return 1 } } } 54 return 0 55} 56// recursive walk: st[0]=files scanned, st[1]=edges added 57func egb_walk(g: *EcoGraph, path: *u8, path_n: i64, filebuf: *u8, aoff: *i64, alen: *i64, st: *i64) -> i64 { 58 if path_n > EGB_MAGIC_3900 { return 0 } 59 path[path_n] = 0 as u8 60 let fd: i64 = sys_openat_rd(path) 61 if fd < 0 { return 0 } 62 let dbuf: *u8 = sys_mmap(EGB_MAGIC_131072) 63 var go: i64 = 1 64 while go == 1 { 65 let nr: i64 = sys_getdents64(fd, dbuf, EGB_MAGIC_131072) 66 if nr <= 0 { go = 0 } else { 67 var off: i64 = 0 68 while off < nr { 69 let rec: *u8 = ((dbuf as i64) + off) as *u8 70 let ty: i64 = dirent_type(rec) 71 let nm: *u8 = dirent_name(rec) 72 if egb_isdotdot(nm) == 0 { 73 let cs: i64 = egb_join(path, path_n, nm) 74 if ty == 4 { 75 egb_walk(g, path, cs, filebuf, aoff, alen, st) 76 } else { 77 let nmn: i64 = bslen(nm) 78 if egb_is_nx(nm, nmn) == 1 { 79 let fnode: i64 = eg_intern(g, nm, nmn) 80 if fnode >= 0 { 81 path[cs] = 0 as u8 82 let flen: i64 = egb_read(path, filebuf, EGB_FILECAP) 83 if flen > 0 { 84 let ic: i64 = nis_scan(filebuf, flen, aoff, alen, EGB_MAGIC_1024) 85 var k: i64 = 0 86 while k < ic { 87 // basename of the import path (strip dir prefix) 88 let io: i64 = aoff[k] 89 let il: i64 = alen[k] 90 var bs: i64 = io 91 var j: i64 = io 92 while j < io + il { if filebuf[j] == (47 as u8) { bs = j + 1 } j = j + 1 } 93 let bl: i64 = (io + il) - bs 94 let inode: i64 = eg_intern(g, ((filebuf as i64)+bs) as *u8, bl) 95 if inode >= 0 { eg_add_edge(g, fnode, inode); st[1] = st[1] + 1 } 96 k = k + 1 97 } 98 st[0] = st[0] + 1 99 } 100 } 101 } 102 } 103 } 104 off = off + dirent_reclen(rec) 105 } 106 } 107 } 108 sys_close(fd) 109 sys_munmap(dbuf, EGB_MAGIC_131072) 110 return 0 111} 112 113func egb_printname(g: *EcoGraph, idx: i64) -> i64 { 114 let off: i64 = g.node_off[idx] 115 var i: i64 = 0 116 while g.arena[off+i] != (0 as u8) { i = i + 1 } 117 sys_write(1, ((g.arena as i64)+off) as *u8, i) 118 return 0 119} 120 121func bq() -> i64 { let c: *u8 = sys_mmap(1); c[0] = 34 as u8; sys_write(1, c, 1); return 0 } 122func egb_jname(g: *EcoGraph, idx: i64) -> i64 { bq(); egb_printname(g, idx); bq(); return 0 } 123// R1-b: emit the query result as JSON (the API/MCP response contract) from a LOADED store. 124func egb_json_query(g: *EcoGraph, q: *u8) -> i64 { 125 let qi: i64 = eg_find(g, q, bslen(q)) 126 bw("{" as *u8); bq(); bw("node" as *u8); bq(); bw(":" as *u8); bq(); bw(q); bq() 127 if qi < 0 { bw("," as *u8); bq(); bw("found" as *u8); bq(); bw(":false}\n" as *u8); return 0 } 128 bw("," as *u8); bq(); bw("found" as *u8); bq(); bw(":true," as *u8); bq(); bw("ca" as *u8); bq(); bw(":" as *u8); bn(eg_ca(g, qi)) 129 bw("," as *u8); bq(); bw("ce" as *u8); bq(); bw(":" as *u8); bn(eg_ce(g, qi)) 130 bw("," as *u8); bq(); bw("orphan" as *u8); bq(); bw(":" as *u8) 131 if eg_ca(g, qi) == 0 { bw("true" as *u8) } else { bw("false" as *u8) } 132 let vis: *u8 = sys_mmap(EGB_MAXNODE) 133 let out: *i64 = sys_mmap(EGB_MAXNODE*8) as *i64 134 let on: *i64 = sys_mmap(8) as *i64 135 var z: i64 = 0 136 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 137 on[0] = 0; vis[qi] = 1 as u8 138 eg_ancestors(g, qi, vis, out, on, EGB_MAXNODE) 139 bw("," as *u8); bq(); bw("roots_to_god" as *u8); bq(); bw(":[" as *u8) 140 var k: i64 = 0 141 while k < on[0] { if k > 0 { bw("," as *u8) } egb_jname(g, out[k]); k = k + 1 } 142 bw("]" as *u8) 143 z = 0 144 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 145 on[0] = 0; vis[qi] = 1 as u8 146 eg_descendants(g, qi, vis, out, on, EGB_MAXNODE) 147 bw("," as *u8); bq(); bw("children_count" as *u8); bq(); bw(":" as *u8); bn(on[0]) 148 bw("," as *u8); bq(); bw("children" as *u8); bq(); bw(":[" as *u8) 149 k = 0 150 while k < on[0] { if k < 200 { if k > 0 { bw("," as *u8) } egb_jname(g, out[k]) } k = k + 1 } 151 bw("]}\n" as *u8) 152 return 0 153} 154 155func main(argc: i64, argv: *i64) -> i64 { 156 if argc < 2 { bw("usage: nx_eco_graph_build <root> [query] [save-prefix] | --load <store-prefix> <query>\n" as *u8); return 2 } 157 let a1: *u8 = argv[1] as *u8 158 // ---- QUERY-ONLY from the SOVEREIGN seg_store (no walk; pure JSON = the API/MCP entry) ---- 159 if a1[0] == (45 as u8) { 160 if argc < 4 { bw("usage: nx_eco_graph_build --load <store-prefix> <query>\n" as *u8); return 2 } 161 let gl: *EcoGraph = eg_load(argv[2] as *u8) 162 if (gl as i64) == 0 { bw("{" as *u8); bq(); bw("error" as *u8); bq(); bw(":" as *u8); bq(); bw("store_not_found" as *u8); bq(); bw("}\n" as *u8); return 3 } 163 egb_json_query(gl, argv[3] as *u8) 164 return 0 165 } 166 let root: *u8 = argv[1] as *u8 167 let g: *EcoGraph = eg_new(EGB_MAXNODE, EGB_MAXEDGE, EGB_ARENA, EGB_HASH) 168 let path: *u8 = sys_mmap(EGB_MAGIC_4096) 169 var rn: i64 = 0 170 while root[rn] != (0 as u8) { path[rn] = root[rn]; rn = rn + 1 } 171 let filebuf: *u8 = sys_mmap(EGB_FILECAP) 172 let aoff: *i64 = sys_mmap(EGB_MAGIC_1024*8) as *i64 173 let alen: *i64 = sys_mmap(EGB_MAGIC_1024*8) as *i64 174 let st: *i64 = sys_mmap(16) as *i64 175 st[0] = 0; st[1] = 0 176 bw("=== nx_eco_graph_build: living ecosystem graph over " as *u8); bw(root); bw(" ===\n" as *u8) 177 egb_walk(g, path, rn, filebuf, aoff, alen, st) 178 eg_finalize(g) // R0b: CSR adjacency + degree arrays -> O(1) coupling, O(reachable) traversals at 16k scale 179 bw(" nodes=" as *u8); bn(g.node_count); bw(" edges=" as *u8); bn(g.edge_count); bw(" files_scanned=" as *u8); bn(st[0]); bw("\n" as *u8) 180 if argc >= 4 { eg_save(g, argv[3] as *u8); bw(" SAVED to sovereign seg_store: " as *u8); bw(argv[3] as *u8); bw("\n" as *u8) } 181 182 // orphan count (Ca==0) + top hub (max Ca) 183 var orphans: i64 = 0 184 var hub: i64 = 0 185 var hubca: i64 = 0 186 var i: i64 = 0 187 while i < g.node_count { 188 let ca: i64 = eg_ca(g, i) 189 if ca == 0 { orphans = orphans + 1 } 190 if ca > hubca { hubca = ca; hub = i } 191 i = i + 1 192 } 193 bw(" top hub (most imported): " as *u8); egb_printname(g, hub); bw(" (Ca=" as *u8); bn(hubca); bw(") Ca==0 nodes=" as *u8); bn(orphans); bw(" (entry-points + orphans)\n" as *u8) 194 195 if argc >= 3 { 196 let q: *u8 = argv[2] as *u8 197 let qi: i64 = eg_intern(g, q, bslen(q)) 198 bw("\n QUERY " as *u8); bw(q); bw(" Ca(importers)=" as *u8); bn(eg_ca(g, qi)); bw(" Ce(imports)=" as *u8); bn(eg_ce(g, qi)); bw("\n" as *u8) 199 let vis: *u8 = sys_mmap(EGB_MAXNODE) 200 let out: *i64 = sys_mmap(EGB_MAXNODE*8) as *i64 201 let on: *i64 = sys_mmap(8) as *i64 202 // roots-to-god 203 var z: i64 = 0 204 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 205 on[0] = 0; vis[qi] = 1 as u8 206 eg_ancestors(g, qi, vis, out, on, EGB_MAXNODE) 207 bw(" ROOTS-TO-GOD (" as *u8); bn(on[0]); bw(" transitive ancestors):\n " as *u8) 208 var k: i64 = 0 209 while k < on[0] { egb_printname(g, out[k]); bw(" " as *u8); k = k + 1 } 210 bw("\n" as *u8) 211 // children-to-newest 212 z = 0 213 while z < g.node_count { vis[z] = 0 as u8; z = z + 1 } 214 on[0] = 0; vis[qi] = 1 as u8 215 eg_descendants(g, qi, vis, out, on, EGB_MAXNODE) 216 bw(" CHILDREN-TO-NEWEST (" as *u8); bn(on[0]); bw(" transitive importers):\n " as *u8) 217 k = 0 218 while k < on[0] { if k < 40 { egb_printname(g, out[k]); bw(" " as *u8) } k = k + 1 } 219 if on[0] > 40 { bw("... (+" as *u8); bn(on[0]-40); bw(" more)" as *u8) } 220 bw("\n" as *u8) 221 } 222 bw("=== eco-graph built (living: re-run to refresh; brick-3 live) ===\n" as *u8) 223 return 0 224}