code wiki / _hdl_build / nx_build_imports_gate.nx
nx_build_imports_gate.nx source
↩ module page · 173 lines · 8956 B
1// nx_build_imports_gate.nx -- SECOND genealogy LENS (operator: "multiple ways to look at ancestors and
2// descendants, fine with all ... rooted from god so we can rebuild anything"). Where nx_build_lineage_gate
3// gives the genesis-anchor view (organ -> DESC-ORGANS -> god), THIS gives the IMPORT-DEPENDENCY view = the
4// REAL rebuild DAG: an organ's true ancestors are the organs it `import`s, recursively, bottoming out at
5// nx_syscalls (the toolchain leaf, which roots to god via DESC-TOOLCHAIN). To REBUILD an organ you must
6// first build its imports -> the import graph IS the rebuild order. A dangling import (names a file that
7// does not exist) = a broken-lineage orphan = forbidden.
8// BOTH directions: ANCESTORS(organ) = its imports; DESCENDANTS(lib) = who imports it.
9// GATE w/ NEG-CONTROL: GREEN iff EVERY registered organ's imports all RESOLVE (0 dangling) AND a bogus
10// import name is detected as unresolvable. Self-contained. license_tier: ORIGINAL expect_exit: 0
11import "nx_syscalls.nx"
12
13const REG: *u8 = "knowledge/registry/build_registry.log"
14const FB: i64 = 262144
15const MAXO: i64 = 8192
16const SLOT: i64 = 160
17
18func ip(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
19func ilen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
20func ipn(v: i64) -> i64 {
21 let bb: *u8 = sys_mmap(28); var m: i64 = v
22 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
23 let t: *u8 = sys_mmap(28); var k: i64 = 0
24 if m == 0 { t[0] = 48 as u8; k = 1 }
25 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
26 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
27 sys_write(1, bb, k); return 0
28}
29func istreq(a: *u8, b: *u8) -> i64 {
30 var i: i64 = 0
31 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
32 if b[i] != (0 as u8) { return 0 }
33 return 1
34}
35func iread(path: *u8, buf: *u8, cap: i64) -> i64 {
36 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 - 1 }
37 var total: i64 = 0; var nrd: i64 = sys_read(fd, buf, cap)
38 while nrd > 0 { total = total + nrd; if total >= cap { nrd = 0 } else { nrd = sys_read(fd, ((buf as i64) + total) as *u8, cap - total) } }
39 sys_close(fd); return total
40}
41func iexists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
42func ijoin(pfx: *u8, name: *u8, out: *u8) -> i64 {
43 var o: i64 = 0; var i: i64 = 0
44 while pfx[i] != (0 as u8) { out[o] = pfx[i]; o = o + 1; i = i + 1 }
45 i = 0; while name[i] != (0 as u8) { out[o] = name[i]; o = o + 1; i = i + 1 }
46 out[o] = 0 as u8; return 0
47}
48// resolve an import name to a real file in runtime/_hdl_build or runtime. 1 if it exists.
49func iresolve(name: *u8) -> i64 {
50 let p: i64 = sys_mmap(512) as i64
51 ijoin("runtime/_hdl_build/" as *u8, name, p as *u8); if iexists(p as *u8) == 1 { return 1 }
52 ijoin("runtime/" as *u8, name, p as *u8); if iexists(p as *u8) == 1 { return 1 }
53 return 0
54}
55// set out to the existing path of organ `name` (try _hdl_build then runtime). 1 if found.
56func iorgan_path(name: *u8, out: *u8) -> i64 {
57 ijoin("runtime/_hdl_build/" as *u8, name, out); if iexists(out) == 1 { return 1 }
58 ijoin("runtime/" as *u8, name, out); if iexists(out) == 1 { return 1 }
59 return 0
60}
61func ifind(buf: *u8, from: i64, to: i64, pat: *u8) -> i64 {
62 let pl: i64 = ilen(pat); if pl == 0 { return 0 - 1 }
63 var i: i64 = from
64 while i + pl <= to { var j: i64 = 0; var ok: i64 = 1; while j < pl { if buf[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } } if ok == 1 { return i } i = i + 1 }
65 return 0 - 1
66}
67// scan a file's bytes for import "<name>" -> out[] names (ptrs). returns count.
68func imp_scan(buf: *u8, n: i64, out: *i64, cap: i64) -> i64 {
69 var cnt: i64 = 0; var i: i64 = 0
70 while i < n {
71 let pos: i64 = ifind(buf, i, n, "import " as *u8)
72 if pos < 0 { i = n } else {
73 // find the opening quote (char 34) after "import "
74 var q: i64 = pos + 7; var g: i64 = 1
75 while g == 1 { if q >= n { g = 0 } else { if buf[q] == (34 as u8) { g = 0 } else { q = q + 1 } } }
76 if q < n {
77 var s: i64 = q + 1; var o: i64 = 0; let nb: *u8 = sys_mmap(SLOT); var g2: i64 = 1
78 while g2 == 1 { if s >= n { g2 = 0 } else { if buf[s] == (34 as u8) { g2 = 0 } else { if o < SLOT - 1 { nb[o] = buf[s]; o = o + 1 } s = s + 1 } } }
79 nb[o] = 0 as u8
80 if o > 0 { if cnt < cap { out[cnt] = nb as i64; cnt = cnt + 1 } }
81 i = s + 1
82 } else { i = n }
83 }
84 }
85 return cnt
86}
87// does organ file `organ` import `target`?
88func imports_target(organ: *u8, target: *u8) -> i64 {
89 let op: *u8 = sys_mmap(512)
90 if iorgan_path(organ, op) == 0 { return 0 }
91 let buf: *u8 = sys_mmap(FB); let n: i64 = iread(op, buf, FB)
92 if n <= 0 { return 0 }
93 let imps: *i64 = sys_mmap(8 * 64) as *i64
94 let ic: i64 = imp_scan(buf, n, imps, 64)
95 var k: i64 = 0
96 while k < ic { if istreq(imps[k] as *u8, target) == 1 { return 1 } k = k + 1 }
97 return 0
98}
99
100func main() -> i64 {
101 ip("=== nx_build_imports_gate: IMPORT-DEPENDENCY genealogy (the real rebuild DAG) ===\n" as *u8)
102 let rbuf: *u8 = sys_mmap(FB); let rn: i64 = iread(REG, rbuf, FB)
103 if rn <= 0 { ip(" ERROR: no build registry\n" as *u8); sys_exit(2); return 2 }
104
105 // distinct registered organ names
106 let names: *i64 = sys_mmap(8 * MAXO) as *i64
107 var cnt: i64 = 0; var i: i64 = 0
108 while i < rn {
109 let ls: i64 = i; var le: i64 = ls; var g: i64 = 1
110 while g == 1 { if le >= rn { g = 0 } else { if rbuf[le] == (10 as u8) { g = 0 } else { le = le + 1 } } }
111 let kp: i64 = ifind(rbuf, ls, le, "organ=" as *u8)
112 if kp >= 0 {
113 var v: i64 = kp + 6; var o: i64 = 0; let ob: *u8 = sys_mmap(SLOT)
114 while v < le { if rbuf[v] == (32 as u8) { v = le } else { if o < SLOT - 1 { ob[o] = rbuf[v]; o = o + 1 } v = v + 1 } }
115 ob[o] = 0 as u8
116 var found: i64 = 0; var k: i64 = 0
117 while k < cnt { if istreq(names[k] as *u8, ob) == 1 { found = 1; k = cnt } else { k = k + 1 } }
118 if found == 0 { if cnt < MAXO { names[cnt] = ob as i64; cnt = cnt + 1 } }
119 }
120 i = le + 1
121 }
122
123 // verify EVERY registered organ's imports resolve (0 dangling = no broken lineage)
124 var total_imp: i64 = 0; var dangling: i64 = 0
125 var di: i64 = 0
126 while di < cnt {
127 let op: *u8 = sys_mmap(512)
128 if iorgan_path(names[di] as *u8, op) == 1 {
129 let buf: *u8 = sys_mmap(FB); let n: i64 = iread(op, buf, FB)
130 let imps: *i64 = sys_mmap(8 * 64) as *i64
131 let ic: i64 = imp_scan(buf, n, imps, 64)
132 var k: i64 = 0
133 while k < ic {
134 total_imp = total_imp + 1
135 if iresolve(imps[k] as *u8) == 0 { dangling = dangling + 1; ip(" DANGLING import: " as *u8); ip(names[di] as *u8); ip(" -> " as *u8); ip(imps[k] as *u8); ip("\n" as *u8) }
136 k = k + 1
137 }
138 }
139 di = di + 1
140 }
141 ip(" registered organs=" as *u8); ipn(cnt); ip(" total import edges=" as *u8); ipn(total_imp); ip(" DANGLING(broken lineage)=" as *u8); ipn(dangling); ip("\n" as *u8)
142
143 // ANCESTORS view: the direct imports of one organ = what you must build first to rebuild it
144 ip(" ANCESTORS(nx_build_registry.nx) [imports = rebuild-first]: " as *u8)
145 let op2: *u8 = sys_mmap(512)
146 if iorgan_path("nx_build_registry.nx" as *u8, op2) == 1 {
147 let buf2: *u8 = sys_mmap(FB); let n2: i64 = iread(op2, buf2, FB)
148 let imps2: *i64 = sys_mmap(8 * 64) as *i64; let ic2: i64 = imp_scan(buf2, n2, imps2, 64)
149 var k: i64 = 0
150 while k < ic2 { ip(imps2[k] as *u8); ip(" " as *u8); k = k + 1 }
151 }
152 ip("\n" as *u8)
153
154 // DESCENDANTS view: who imports the lib (the other direction)
155 ip(" DESCENDANTS(nx_build_registry_lib.nx) [who imports it]: " as *u8)
156 var dd: i64 = 0
157 while dd < cnt { if imports_target(names[dd] as *u8, "nx_build_registry_lib.nx" as *u8) == 1 { ip(names[dd] as *u8); ip(" " as *u8) } dd = dd + 1 }
158 ip("\n" as *u8)
159
160 // NEG-CONTROL: a bogus import name must NOT resolve; a real leaf must.
161 let nc_bad: i64 = iresolve("nx_zzz_nonexistent_organ.nx" as *u8)
162 let nc_good: i64 = iresolve("nx_syscalls.nx" as *u8)
163 ip(" neg-control: resolve(bogus)=" as *u8); ipn(nc_bad); ip(" (expect 0) resolve(nx_syscalls.nx)=" as *u8); ipn(nc_good); ip(" (expect 1)\n" as *u8)
164
165 var ok: i64 = 1
166 if dangling != 0 { ok = 0 }
167 if nc_bad != 0 { ok = 0 }
168 if nc_good != 1 { ok = 0 }
169 ip(" verdict=" as *u8)
170 if ok == 1 { ip("GREEN (every organ's imports resolve = rebuildable DAG; dangling rejected)\n" as *u8); sys_exit(0); return 0 }
171 ip("RED (a dangling import = broken lineage, or neg-control disarmed)\n" as *u8)
172 sys_exit(1); return 1
173}