code wiki / _hdl_build / nx_json_lib.nx
nx_json_lib.nx source
↩ module page · 75 lines · 3443 B
1// nx_json_lib.nx -- minimal SOVEREIGN JSON field reader (no jq, no shell, no 3rd-party). Built for
2// the work-journal: extract "transcript_path" from a Claude-Code hook's stdin JSON and scan tool_use
3// blocks out of the session transcript .jsonl. NOT a full JSON parser -- it linearly finds
4// "key":"value" string fields and literal anchors, which is exactly what capture needs and is robust
5// to the harness's compact (space-free) emission. De-escapes backslash sequences and neutralizes any
6// TAB/NL/CR so an extracted value can never tear the TSV work-journal line.
7// Sovereign: imports nx_syscalls only. license_tier: ORIGINAL
8import "nx_syscalls.nx"
9
10func jx_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
11
12// first index of NUL-term `pat` in buf[start..n), or -1.
13func jx_find(buf: *u8, n: i64, start: i64, pat: *u8) -> i64 {
14 let pl: i64 = jx_len(pat)
15 if pl == 0 { return 0 - 1 }
16 var i: i64 = start
17 if i < 0 { i = 0 }
18 while i + pl <= n {
19 var j: i64 = 0
20 var ok: i64 = 1
21 while j < pl { if buf[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } }
22 if ok == 1 { return i }
23 i = i + 1
24 }
25 return 0 - 1
26}
27
28// copy a JSON string value starting at vstart (the byte right after the opening quote) into out,
29// de-escaping backslashes and forcing TAB/NL/CR -> space (TSV-safe), bounded by outcap-1, NUL-term.
30// returns index just past the closing quote, or -1 if unterminated within buf.
31func jx_copy_str(buf: *u8, n: i64, vstart: i64, out: *u8, outcap: i64) -> i64 {
32 var i: i64 = vstart
33 var o: i64 = 0
34 while i < n {
35 let c: i64 = buf[i] as i64
36 if c == 92 { // backslash escape
37 if i + 1 < n {
38 var e: i64 = buf[i + 1] as i64
39 if e == 116 { e = 32 } // \t -> space
40 if e == 110 { e = 32 } // \n -> space
41 if e == 114 { e = 32 } // \r -> space
42 if o < outcap - 1 { out[o] = e as u8; o = o + 1 }
43 i = i + 2
44 } else { i = i + 1 }
45 } else {
46 if c == 34 { out[o] = 0 as u8; return i + 1 } // closing quote
47 var cc: i64 = c
48 if cc == 9 { cc = 32 }
49 if cc == 10 { cc = 32 }
50 if cc == 13 { cc = 32 }
51 if o < outcap - 1 { out[o] = cc as u8; o = o + 1 }
52 i = i + 1
53 }
54 }
55 out[o] = 0 as u8
56 return 0 - 1
57}
58
59// find `"key":"` at/after `start`, copy its string value into out. returns index past the value's
60// closing quote, or -1 if not found. `key` is the bare name (no quotes); harness JSON is compact.
61func jx_get_str(buf: *u8, n: i64, start: i64, key: *u8, out: *u8, outcap: i64) -> i64 {
62 let kl: i64 = jx_len(key)
63 let needle: *u8 = sys_mmap(kl + 8)
64 var o: i64 = 0
65 needle[o] = 34 as u8; o = o + 1 // "
66 var i: i64 = 0
67 while key[i] != (0 as u8) { needle[o] = key[i]; o = o + 1; i = i + 1 }
68 needle[o] = 34 as u8; o = o + 1 // "
69 needle[o] = 58 as u8; o = o + 1 // :
70 needle[o] = 34 as u8; o = o + 1 // "
71 needle[o] = 0 as u8
72 let at: i64 = jx_find(buf, n, start, needle)
73 if at < 0 { return 0 - 1 }
74 return jx_copy_str(buf, n, at + o, out, outcap) // o = needle length; value starts after it
75}