code wiki / _hdl_build / nx_code_depgraph.nx
nx_code_depgraph.nx source
↩ module page · 106 lines · 5463 B
1// nx_code_depgraph.nx -- Analyzes source code to build a dependency graph of modules, identifying relationships and architectural hubs.
2import "nx_gate_gn.nx"
3import "nx_gate_base.nx"
4// nx_code_depgraph.nx -- NISHI code-analysis, the dependency/architecture-graph rung (vs Understand/Structure101).
5// Walks a repo's source files (nx_dir), extracts each file's #include "..."/<...> and import directives as
6// dependency EDGES, and reports the graph: modules (files), edges (deps), density, and the top HUB (the most
7// depended-on module = the architectural center). Sovereign, integer, zero egress. usage:
8// nx_code_depgraph <repo-dir> license_tier: ORIGINAL
9import "nx_syscalls.nx"
10import "nx_dir.nx"
11const K_MAGIC_8192: i64 = 8192
12const K_MAGIC_2097152: i64 = 2097152
13const K_MAGIC_4096: i64 = 4096
14
15func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
16" as *u8); return ok }
17func match_at(buf: *u8, n: i64, i: i64, pat: *u8) -> i64 { var j: i64=0; while pat[j]!=(0 as u8){ if i+j>=n {return 0} if buf[i+j]!=pat[j]{return 0} j=j+1 } return 1 }
18
19const MAXT: i64 = 65536
20const ARENA: i64 = 8388608
21
22func main(argc: i64, argv: *i64) -> i64 {
23 if argc < 2 { gw("usage: nx_code_depgraph <repo-dir>\n"); return 2 }
24 let dir: *u8 = argv[1] as *u8
25 let rows: *NxDirRow = sys_mmap(K_MAGIC_8192 * NX_DIR_ROW_BYTES) as *NxDirRow
26 let na: *u8 = sys_mmap(K_MAGIC_2097152)
27 let res: *NxDirResult = sys_mmap(NX_DIR_RESULT_BYTES) as *NxDirResult
28 let v: i64 = nx_dir_list(dir, rows, K_MAGIC_8192, na, K_MAGIC_2097152, 0, res)
29 if v != NX_DIR_OK { if v != NX_DIR_TRUNCATED { gw("DEPGRAPH: dir list failed ("); gn(v); gw(")\n"); return 1 } }
30 let nfiles: i64 = res.n_filled
31
32 let arena: *u8 = sys_mmap(ARENA); var au: i64 = 0
33 let toff: *i64 = sys_mmap(MAXT*8) as *i64
34 let tlen: *i64 = sys_mmap(MAXT*8) as *i64
35 var nt: i64 = 0
36
37 let lenp: *i64 = sys_mmap(16) as *i64
38 let path: *u8 = sys_mmap(K_MAGIC_4096)
39 var dl: i64 = 0; while dir[dl]!=(0 as u8){dl=dl+1}
40 var idx: i64 = 0
41 while idx < nfiles {
42 let row: *NxDirRow = nx_dir_row_at(rows, idx)
43 if nx_dir_row_is_regular_file(row) == 1 {
44 var p: i64=0; while p<dl{path[p]=dir[p];p=p+1} path[p]=47 as u8; p=p+1
45 var q: i64=0; while q<row.name_len{path[p]=row.name_ptr[q];p=p+1;q=q+1} path[p]=0 as u8
46 let fb: *u8 = sys_read_file(path, lenp)
47 if (fb as i64) != 0 {
48 let flen: i64 = lenp[0]
49 var i: i64 = 0
50 while i < flen {
51 var s: i64 = 0 - 1; var e: i64 = 0
52 if match_at(fb, flen, i, "#include" as *u8) == 1 {
53 var j: i64 = i+8; while j<flen { if fb[j]==32 as u8 { j=j+1 } else { if fb[j]==9 as u8 { j=j+1 } else { break } } }
54 if fb[j]==34 as u8 { s=j+1; e=s; while e<flen { if fb[e]==34 as u8 { break } e=e+1 } }
55 else { if fb[j]==60 as u8 { s=j+1; e=s; while e<flen { if fb[e]==62 as u8 { break } e=e+1 } } }
56 i = j
57 } else { if match_at(fb, flen, i, "import " as *u8) == 1 {
58 var j: i64 = i+7; while j<flen { if fb[j]==32 as u8 { j=j+1 } else { break } }
59 if fb[j]==34 as u8 { s=j+1; e=s; while e<flen { if fb[e]==34 as u8 { break } e=e+1 } }
60 else { s=j; e=s; while e<flen { if fb[e]==32 as u8 { break } if fb[e]==10 as u8 { break } if fb[e]==59 as u8 { break } e=e+1 } }
61 i = j
62 } }
63 if s >= 0 { if e > s {
64 // strip to basename (after last '/')
65 var b: i64 = s; var bs: i64 = s
66 while b < e { if fb[b]==47 as u8 { bs = b+1 } b=b+1 }
67 let tl: i64 = e - bs
68 if nt < MAXT { if au + tl + 1 < ARENA {
69 toff[nt]=au; tlen[nt]=tl
70 var c: i64=0; while c<tl { arena[au+c]=fb[bs+c]; c=c+1 } au=au+tl; nt=nt+1
71 } }
72 } }
73 i = i + 1
74 }
75 sys_munmap(fb, flen)
76 }
77 }
78 idx = idx + 1
79 }
80
81 // top hub = max in-degree over distinct targets (O(nt^2) string compare, bounded)
82 var maxdeg: i64 = 0; var maxidx: i64 = 0
83 var a: i64 = 0
84 while a < nt {
85 var cnt: i64 = 0; var b: i64 = 0
86 while b < nt {
87 if tlen[a]==tlen[b] {
88 var m: i64=0; var same: i64=1
89 while m < tlen[a] { if arena[toff[a]+m] != arena[toff[b]+m] { same=0; break } m=m+1 }
90 if same==1 { cnt=cnt+1 }
91 }
92 b=b+1
93 }
94 if cnt > maxdeg { maxdeg=cnt; maxidx=a }
95 a = a + 1
96 }
97
98 gw("=== DEPGRAPH: "); gw(dir); gw(" ===\n")
99 gw(" modules (source files): "); gn(nfiles); gw("\n")
100 gw(" dependency edges (#include/import): "); gn(nt); gw("\n")
101 if nfiles > 0 { gw(" density (edges*100/module): "); gn(nt*100/nfiles); gw("\n") }
102 if nt > 0 { gw(" top hub (most depended-on): "); sys_write(1, ((arena as i64)+toff[maxidx]) as *u8, tlen[maxidx]); gw(" (in-degree "); gn(maxdeg); gw(")\n") }
103 gw("DEPGRAPH-OK modules="); gn(nfiles); gw(" edges="); gn(nt); gw(" maxindegree="); gn(maxdeg); gw("\n")
104 if nfiles > 0 { return 0 }
105 return 3
106}