code wiki / _hdl_build / nx_doctor_import.nx
nx_doctor_import.nx source
↩ module page · 105 lines · 4828 B
1// nx_doctor_import.nx -- DOCTOR sub-organ (the IMPORT-FIXER role; sibling of nx_doctor_fix). Turns the
2// CC-UNDEFFN known-issue ("call to undefined function: X") from recall-and-REPORT into a real AUTO-FIX
3// for the resolvable case: most such failures are a MISSING IMPORT, and every sys_* primitive lives in
4// nx_syscalls.nx (verified sys_write @ nx_syscalls.nx:79). So: extract the named function from the
5// Engineer's diagnostic, resolve it to the organ that defines it, and write a healed candidate with the
6// import prepended (ADDITIVE -- new file, the protected source is never clobbered).
7//
8// RACI: the Doctor produces a CANDIDATE only; it does NOT verify (the Engineer re-compiles) and does
9// NOT admit (Warden/Council). di_resolve returns 0 for names it cannot resolve -> the caller falls back
10// to recall-and-report (NO false fix -- honest). v1 rule = sys_*->nx_syscalls.nx (deterministic); a
11// general symbol-index over the corpus is the next extension. license_tier: ORIGINAL
12import "nx_syscalls.nx"
13
14func di_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
15
16// local unlinkat(AT_FDCWD,path,0) -- x86_64 raw 263 passthrough (the nx_novel_close.nx:61 precedent),
17// so a gate can clean up its own temp candidates without touching shared nx_syscalls.nx.
18func di_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 }
19
20// first index of needle in hay[0..hlen), or -1
21func di_find(hay: *u8, hlen: i64, needle: *u8) -> i64 {
22 let nlen: i64 = di_len(needle)
23 var i: i64 = 0
24 while i + nlen <= hlen {
25 var m: i64 = 1
26 var j: i64 = 0
27 while j < nlen { if hay[i + j] != needle[j] { m = 0; j = nlen } else { j = j + 1 } }
28 if m == 1 { return i }
29 i = i + 1
30 }
31 return 0 - 1
32}
33
34// extract the function name from a captured "call to undefined function: <name>" diagnostic into out
35// (NUL-terminated); returns its length, or 0 if the diagnostic is not this class.
36func di_undef_fn(diag_path: *u8, out: *u8) -> i64 {
37 let lenp: *i64 = sys_mmap(16) as *i64
38 let buf: *u8 = sys_read_file(diag_path, lenp)
39 let blen: i64 = lenp[0]
40 if blen <= 0 { out[0] = 0 as u8; return 0 }
41 let marker: *u8 = "call to undefined function: " as *u8
42 let at: i64 = di_find(buf, blen, marker)
43 if at < 0 { out[0] = 0 as u8; return 0 }
44 var i: i64 = at + di_len(marker)
45 var o: i64 = 0
46 var go: i64 = 1
47 while go == 1 {
48 if i >= blen { go = 0 } else {
49 let c: i64 = buf[i]
50 if c == 10 { go = 0 } else {
51 if c == 13 { go = 0 } else { out[o] = buf[i]; o = o + 1; i = i + 1 }
52 }
53 }
54 }
55 out[o] = 0 as u8
56 return o
57}
58
59// resolve an undefined-function name to the import that defines it. v1 deterministic rule: a sys_*
60// primitive lives in nx_syscalls.nx. Returns import length (out_import NUL-terminated), or 0 if
61// unresolved (honest -- NO false fix; the caller reports instead). Flat byte checks (avoids the
62// LM-002 deep-nested-if landmine); reads a few bytes past a short name's NUL land on 0 != expected.
63func di_resolve(name: *u8, out_import: *u8) -> i64 {
64 var issys: i64 = 1
65 if name[0] != (115 as u8) { issys = 0 } // 's'
66 if name[1] != (121 as u8) { issys = 0 } // 'y'
67 if name[2] != (115 as u8) { issys = 0 } // 's'
68 if name[3] != (95 as u8) { issys = 0 } // '_'
69 if issys == 1 {
70 let imp: *u8 = "nx_syscalls.nx" as *u8
71 var i: i64 = 0
72 while imp[i] != (0 as u8) { out_import[i] = imp[i]; i = i + 1 }
73 out_import[i] = 0 as u8
74 return i
75 }
76 out_import[0] = 0 as u8
77 return 0
78}
79
80// HEAL: write out_path = `import "<imp>"` + newline + the original source (additive candidate).
81// Returns chars added (= import-line length). The quote bytes are emitted directly (34) to avoid any
82// escaped-quote-in-literal dependency.
83func di_heal(src_path: *u8, out_path: *u8, imp: *u8) -> i64 {
84 let lenp: *i64 = sys_mmap(16) as *i64
85 let src: *u8 = sys_read_file(src_path, lenp)
86 let slen: i64 = lenp[0]
87 let ilen: i64 = di_len(imp)
88 let buf: *u8 = sys_mmap(slen + ilen + 64)
89 var o: i64 = 0
90 let pre: *u8 = "import " as *u8
91 var k: i64 = 0
92 while pre[k] != (0 as u8) { buf[o] = pre[k]; o = o + 1; k = k + 1 }
93 buf[o] = 34 as u8; o = o + 1 // opening quote
94 var ii: i64 = 0
95 while ii < ilen { buf[o] = imp[ii]; o = o + 1; ii = ii + 1 }
96 buf[o] = 34 as u8; o = o + 1 // closing quote
97 buf[o] = 10 as u8; o = o + 1 // newline
98 var t: i64 = 0
99 while t < slen { buf[o] = src[t]; o = o + 1; t = t + 1 }
100 let fd: i64 = sys_openat_wr(out_path, 0x1a4)
101 if fd < 0 { return 0 - 1 }
102 sys_write(fd, buf, o)
103 sys_close(fd)
104 return o - slen
105}