nx_docgen_lib.nx source
↩ module page · 105 lines · 4242 B
1// nx_docgen_lib.nx -- Nishi Office: DOCUMENT ASSEMBLY (F505) core lib. Data-driven clause
2// library + templates (ordered clause refs) + {field} merge -> a deterministic, content-
3// addressed legal document. Legal-SOTA: (1) clauses/templates are DATA on the immutable
4// seg_store (add a clause = a data change, rule-11/rule-25, never fewer options); (2) merge
5// is FAIL-CLOSED -- an unknown clause OR an unfilled {field} REFUSES the whole document
6// (never a silent blank in a contract); (3) same template+data -> same CID (nx_canon_cid),
7// so an assembled engagement letter is tamper-evident and composes with nx_box + nx_sign.
8// Composes nx_matter_lib (mt_field/mt_streq/canon) + nx_registry + nx_canon_cid. LIB. license_tier: ORIGINAL
9
10import "nx_matter_lib.nx"
11
12func dg_strlen(s: *u8) -> i64 {
13 var i: i64 = 0
14 while s[i] != (0 as u8) { i = i + 1 }
15 return i
16}
17
18// store a clause (raw text) on the immutable plane, keyed by id
19func dg_clause_put(prefix: *u8, id: *u8, text: *u8) -> i64 {
20 return reg_put(prefix, "clause:" as *u8, "clause:__idx__" as *u8, id, text, dg_strlen(text))
21}
22
23// store a template = ordered comma-separated clause ids
24func dg_tmpl_put(prefix: *u8, id: *u8, csv: *u8) -> i64 {
25 return reg_put(prefix, "tmpl:" as *u8, "tmpl:__idx__" as *u8, id, csv, dg_strlen(csv))
26}
27
28// append src to dst[o..], substituting every {field} from the canonical merge record.
29// returns the new offset, or -1 if a {field} is absent (FAIL-CLOSED, no silent blank).
30func dg_merge(src: *u8, srclen: i64, mergerec: *u8, mergelen: i64, dst: *u8, o0: i64) -> i64 {
31 var o: i64 = o0
32 var i: i64 = 0
33 let tok: *u8 = sys_mmap(128)
34 let val: *u8 = sys_mmap(512)
35 while i < srclen {
36 let c: i64 = src[i] as i64
37 if c == 123 {
38 var j: i64 = i + 1
39 var found: i64 = 0
40 while found == 0 {
41 if j >= srclen { found = 2 }
42 if found == 0 { if (src[j] as i64) == 125 { found = 1 } }
43 if found == 0 { j = j + 1 }
44 }
45 if found == 2 { dst[o] = src[i]; o = o + 1; i = i + 1 }
46 if found == 1 {
47 var k: i64 = 0
48 var p: i64 = i + 1
49 while p < j { tok[k] = src[p]; k = k + 1; p = p + 1 }
50 tok[k] = 0 as u8
51 let vl: i64 = mt_field(mergerec, mergelen, tok, k, val)
52 if vl < 0 { return 0 - 1 }
53 var d: i64 = 0
54 while d < vl { dst[o] = val[d]; o = o + 1; d = d + 1 }
55 i = j + 1
56 }
57 }
58 if c != 123 { dst[o] = src[i]; o = o + 1; i = i + 1 }
59 }
60 return o
61}
62
63// assemble template tmpl_id with the merge record into out (NUL-terminated); returns length,
64// or -1 if the template/a clause is unknown OR a merge field is unfilled (FAIL-CLOSED).
65func dg_assemble(prefix: *u8, tmpl_id: *u8, mergerec: *u8, mergelen: i64, out: *u8) -> i64 {
66 let po: *i64 = sys_mmap(16) as *i64
67 let lo: *i64 = sys_mmap(16) as *i64
68 if reg_get(prefix, "tmpl:" as *u8, tmpl_id, po, lo) != 1 { return 0 - 1 }
69 let csv: *u8 = po[0] as *u8
70 let csvlen: i64 = lo[0]
71 var o: i64 = 0
72 var s: i64 = 0
73 while s < csvlen {
74 var e: i64 = s
75 var done: i64 = 0
76 while done == 0 {
77 if e >= csvlen { done = 1 }
78 if done == 0 { if (csv[e] as i64) == 44 { done = 1 } else { e = e + 1 } }
79 }
80 let cid: *u8 = sys_mmap(128)
81 var k: i64 = 0
82 var p: i64 = s
83 while p < e { cid[k] = csv[p]; k = k + 1; p = p + 1 }
84 cid[k] = 0 as u8
85 let cpo: *i64 = sys_mmap(16) as *i64
86 let clo: *i64 = sys_mmap(16) as *i64
87 if reg_get(prefix, "clause:" as *u8, cid, cpo, clo) != 1 { return 0 - 1 }
88 let no: i64 = dg_merge(cpo[0] as *u8, clo[0], mergerec, mergelen, out, o)
89 if no < 0 { return 0 - 1 }
90 o = no
91 out[o] = 10 as u8
92 o = o + 1
93 s = e + 1
94 }
95 out[o] = 0 as u8
96 return o
97}
98
99// count '{' left in a doc (0 == every merge field was substituted)
100func dg_unmerged(doc: *u8, len: i64) -> i64 {
101 var n: i64 = 0
102 var i: i64 = 0
103 while i < len { if (doc[i] as i64) == 123 { n = n + 1 } i = i + 1 }
104 return n
105}