code wiki / (root) / nx_substrate_diagram.nx

nx_substrate_diagram.nx source

↩ module page · 242 lines · 9153 B

1// nx_substrate_diagram.nx -- substrate-walker that BUILDS an 2// nx_diagram and emits any of 4 formats (Mermaid / DOT / ASCII / JSON). 3// 4// Refactored 2026-05-13 to consume the nx_diagram primitive instead 5// of hand-rolling Mermaid output. Reduces ~260 LOC to ~170 LOC and 6// gives the substrate-walker 4 output formats for free. 7// 8// DEFAULT EMITTER: Mermaid (backward-compatible with prior tool). 9// To emit other formats, edit the call near the bottom of main() -- 10// nx_diagram_emit_dot(d) / nx_diagram_emit_ascii(d) / nx_diagram_emit_json(d). 11// 12// genealogy_id: mermaid_2015_javascript_diagram_text + graphviz_dot 13// + plain_text_diagram_lineage 14// lineage_id: graph_visualization_text_format 15// axioms: NX_AX_REL_TRANSITIVITY (depends-on transitive) 16 17// nx_safety_envelope: 18// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 19// sil_target: SIL1 20// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 21// verdict: NOT_YET_EVALUATED 22 23import "nx_syscalls.nx" 24import "nx_runtime.nx" 25import "nx_axioms.nx" 26import "nx_dirent.nx" 27import "nx_fcntl.nx" 28import "nx_tier.nx" 29import "nx_diagram.nx" 30 31const NX_DIA_MAX_MODULES: nx_idx = 400 32const NX_DIA_MAX_EDGES: nx_idx = 4096 33const NX_DIA_MAX_NAME: nx_size = 96 34const NX_DIA_DIR_BUF: nx_size = 16384 35 36// ===== filename pattern ================================================= 37 38func dia_name_matches(name: *u8, name_len: nx_size) -> nx_int { 39 if name_len < 6 { return 0 } 40 if name[0] != 110 { return 0 } // 'n' 41 if name[1] != 120 { return 0 } // 'x' 42 if name[2] != 95 { return 0 } // '_' 43 if name[name_len - 3] != 46 { return 0 } // '.' 44 if name[name_len - 2] != 110 { return 0 } // 'n' 45 if name[name_len - 1] != 120 { return 0 } // 'x' 46 // reject _test.nx 47 if name_len >= 8 { 48 if name[name_len - 8] == 95 { 49 if name[name_len - 7] == 116 { 50 if name[name_len - 6] == 101 { 51 if name[name_len - 5] == 115 { 52 if name[name_len - 4] == 116 { 53 return 0 54 } 55 } 56 } 57 } 58 } 59 } 60 return 1 61} 62 63func dia_module_from_filename(name: *u8, name_len: nx_size, out: *u8) -> nx_size { 64 let mod_len: nx_size = name_len - 3 65 var i: nx_idx = 0 66 while i < mod_len { 67 out[i] = name[i] 68 i = i + 1 69 } 70 out[mod_len] = 0 71 return mod_len 72} 73 74// ===== directory walk -> Diagram nodes ================================== 75 76func dia_collect_into_diagram(dir_path: *u8, d: *Diagram, names_buf: *u8) -> nx_idx { 77 let fd: i64 = nx_openat(NX_AT_FDCWD, dir_path, 78 NX_O_RDONLY | NX_O_DIRECTORY, 0) 79 if fd < 0 { return -1 } 80 let buf: *u8 = sys_mmap(NX_DIA_DIR_BUF) 81 let dr_raw: *u8 = sys_mmap(NX_DIRENT_BYTES) 82 let dr: *NxDirent = dr_raw as *NxDirent 83 var added: nx_idx = 0 84 85 var batch: i64 = nx_dirent_read(fd, buf, NX_DIA_DIR_BUF) 86 while batch > 0 { 87 var off: i64 = 0 88 while off < batch { 89 let next_off: i64 = nx_dirent_iter(buf, off, batch, dr) 90 if next_off <= 0 { off = batch + 1 } 91 if off <= batch { 92 let nm_len: nx_size = nx_dirent_name_len(dr) 93 if dia_name_matches(dr.name, nm_len) == 1 { 94 if added < NX_DIA_MAX_MODULES { 95 let dst_addr: i64 = (names_buf as i64) + added * NX_DIA_MAX_NAME 96 let dst: *u8 = dst_addr as *u8 97 dia_module_from_filename(dr.name, nm_len, dst) 98 nx_diagram_add_node(d, dst, "" as *u8) 99 added = added + 1 100 } 101 } 102 off = next_off 103 } 104 } 105 batch = nx_dirent_read(fd, buf, NX_DIA_DIR_BUF) 106 } 107 sys_close(fd) 108 return added 109} 110 111// ===== import parse -> Diagram edges ==================================== 112 113func dia_find_module_idx(d: *Diagram, names_buf: *u8, name: *u8, name_len: nx_size) -> nx_idx { 114 var mi: nx_idx = 0 115 while mi < d.n_nodes { 116 let cand_addr: i64 = (names_buf as i64) + mi * NX_DIA_MAX_NAME 117 let cand: *u8 = cand_addr as *u8 118 let cand_len: nx_size = strlen(cand) 119 if cand_len == name_len { 120 if strneq(cand, name, cand_len) == 1 { return mi } 121 } 122 mi = mi + 1 123 } 124 return -1 125} 126 127func dia_add_edges_for_module(d: *Diagram, names_buf: *u8, from_idx: nx_idx) -> nx_int { 128 let mod_addr: i64 = (names_buf as i64) + from_idx * NX_DIA_MAX_NAME 129 let module: *u8 = mod_addr as *u8 130 131 let path_buf: *u8 = sys_mmap(512) 132 let prefix: *u8 = "nxc2/runtime/" as *u8 133 let plen: nx_size = strlen(prefix) 134 var k: nx_idx = 0 135 while k < plen { path_buf[k] = prefix[k]; k = k + 1 } 136 let mod_len: nx_size = strlen(module) 137 var k2: nx_idx = 0 138 while k2 < mod_len { path_buf[plen + k2] = module[k2]; k2 = k2 + 1 } 139 path_buf[plen + mod_len] = 46 140 path_buf[plen + mod_len + 1] = 110 141 path_buf[plen + mod_len + 2] = 120 142 path_buf[plen + mod_len + 3] = 0 143 144 let out_len: *i64 = (sys_mmap(8)) as *i64 145 out_len[0] = 0 146 let buf: *u8 = sys_read_file(path_buf, out_len) 147 if (buf as i64) == 0 { return 0 } 148 let n: nx_size = out_len[0] 149 150 var pos: nx_idx = 0 151 var emitted: nx_int = 0 152 while pos < n { 153 var eol: nx_idx = pos 154 var done_l: nx_int = 0 155 while done_l == 0 { 156 if eol >= n { done_l = 1 } 157 if done_l == 0 { 158 if buf[eol] == 10 { done_l = 1 } 159 if done_l == 0 { eol = eol + 1 } 160 } 161 } 162 let line_len: nx_size = eol - pos 163 164 if line_len > 10 { 165 if buf[pos] == 105 { if buf[pos+1] == 109 { 166 if buf[pos+2] == 112 { if buf[pos+3] == 111 { 167 if buf[pos+4] == 114 { if buf[pos+5] == 116 { 168 if buf[pos+6] == 32 { 169 var p: nx_idx = pos + 7 170 var done_q: nx_int = 0 171 while done_q == 0 { 172 if p >= eol { done_q = 1 } 173 if done_q == 0 { 174 if buf[p] == 34 { done_q = 1 } 175 if done_q == 0 { p = p + 1 } 176 } 177 } 178 if p < eol { 179 if buf[p] == 34 { 180 p = p + 1 181 let mod_start: nx_idx = p 182 var done_m: nx_int = 0 183 while done_m == 0 { 184 if p >= eol { done_m = 1 } 185 if done_m == 0 { 186 if buf[p] == 34 { done_m = 1 } 187 if done_m == 0 { 188 if buf[p] == 46 { done_m = 1 } 189 if done_m == 0 { p = p + 1 } 190 } 191 } 192 } 193 let mod_end: nx_idx = p 194 let mname_len: nx_size = mod_end - mod_start 195 let mname: *u8 = ((buf as i64) + mod_start) as *u8 196 let to_idx: nx_idx = dia_find_module_idx(d, names_buf, mname, mname_len) 197 if to_idx >= 0 { 198 nx_diagram_add_edge(d, from_idx, to_idx, "" as *u8) 199 emitted = emitted + 1 200 } 201 } 202 } 203 } 204 }} 205 }} 206 }} 207 } 208 pos = eol + 1 209 } 210 return emitted 211} 212 213// ===== entry ============================================================ 214 215func main() -> i64 { 216 let names_buf: *u8 = sys_mmap(NX_DIA_MAX_MODULES * NX_DIA_MAX_NAME) 217 let d: *Diagram = nx_diagram_new(NX_DIA_MAX_MODULES, NX_DIA_MAX_EDGES) 218 219 let n: nx_idx = dia_collect_into_diagram("nxc2/runtime" as *u8, d, names_buf) 220 if n < 0 { 221 println("error: cannot open runtime directory" as *u8) 222 return 1 223 } 224 225 var total_edges: nx_int = 0 226 var j: nx_idx = 0 227 while j < d.n_nodes { 228 total_edges = total_edges + dia_add_edges_for_module(d, names_buf, j) 229 j = j + 1 230 } 231 232 // Default emitter: Mermaid (backward-compatible). 233 // Swap to nx_diagram_emit_dot / _ascii / _json for other formats. 234 nx_diagram_emit_mermaid(d) 235 236 print(" %% " as *u8) 237 print_i64(d.n_nodes) 238 print(" modules, " as *u8) 239 print_i64(total_edges) 240 println(" import edges" as *u8) 241 return 0 242}