nx_accept_ref_lib.nx source
↩ module page · 407 lines · 20329 B
1// nx_accept_ref_lib.nx -- THE VERB-SIDE HALF OF THE THREE-PARTY ACCEPTANCE LEDGER (2026-08-31).
2//
3// nx_accept_lib.nx is the DECISION CORE: three planes in, ACCEPTED or INCOMPLETE out, reason codes in why[].
4// This lib is everything the verbs (nx_accept) and their referee (nx_accept_gate) need ON TOP of that core,
5// kept out of the organ's main() so the gate drives the identical code over /tmp fixtures:
6// * acr_party -- INCOMPLETE is never enough. The FIRST missing signature is NAMED, in the order the
7// operator's standing order lists them (operator, referee, seat), so a NOT-AGREED can
8// always say WHICH negative it is: OPERATOR-MISSING is not OPERATOR-REJECT,
9// REFEREE-BELOW-BAND is not REFEREE-MISSING, and none of them is SEAT-MISSING.
10// * acr_status_line -- one line per subject carrying every input the verdict was derived from (operator
11// verdict and row count, referee code, percept, floor, tier, seat rows, board and organ
12// file), so a reader can refute the verdict from the line instead of trusting it.
13// * acr_unmapped -- an operator row whose targets carry no ga_accept_<subject> token governs NOTHING and
14// the core only COUNTS it. This prints each one with id, verdict, actor, targets and the
15// remedy, because a counted-but-unnamed row is not actionable.
16// * acr_boards -- every ACCEPTANCE watch row on the /compare boards becomes a subject too, so a board
17// subject nobody has judged reads NOT-AGREED missing=OPERATOR-MISSING instead of
18// vanishing from the list, and a watch row naming the WRONG organ file is flagged --
19// it could never flip, however many signatures arrived.
20// * acr_ref_admit -- may a referee row be written for this tier at all? The panel receipt decides
21// (admitted, tiers_admitted, a floor for the tier); an abstaining panel is not a grade.
22// * acr_kvint -- the mid-line key=<int> reader for the panel lens line (cjp_percept=<n>), because
23// nx_lineconf_lib is deliberately LINE-anchored and that field is not at a line start.
24// * acr_sha256_file -- the artifact identity a seat attests to and the frame identity a referee row carries:
25// sha256 of the bytes, hex, never a hand-typed stamp. -1 when unreadable, never the
26// digest of nothing.
27// * acr_decl_shape -- the emitted declaration file's ONE permitted code form, as a ruler: every non-comment
28// line must be exactly `func ga_accept_<ident>() -> i64 { return 1 }`, the form the
29// compiler is proven to accept, so a buffer that passes this ruler is the form that builds.
30// COMPOSES, NEVER RE-IMPLEMENTS: nx_accept_lib for every rule, nx_seg_store's cursor through al_next for the
31// plane walk, nx_comparewatch_lib's cw_field for tab fields, nx_sha256 for the digest.
32// license_tier: ORIGINAL No hw writes (Rule 26).
33import "nx_syscalls.nx"
34import "nx_sha256.nx"
35import "nx_accept_lib.nx"
36
37// the named missing party, first missing wins in operator -> referee -> seat order
38const ACR_P_AGREED: i64 = 0
39const ACR_P_OP_MISSING: i64 = 1
40const ACR_P_OP_REJECT: i64 = 2
41const ACR_P_OP_UNJUDGED: i64 = 3
42const ACR_P_OP_INVALID: i64 = 4
43const ACR_P_REF_MISSING: i64 = 5
44const ACR_P_REF_BAD: i64 = 6
45const ACR_P_REF_INVALID: i64 = 7
46const ACR_P_REF_PANEL: i64 = 8
47const ACR_P_REF_TIER: i64 = 9
48const ACR_P_REF_NOFLOOR: i64 = 10
49const ACR_P_REF_BELOW: i64 = 11
50const ACR_P_SEAT_MISSING: i64 = 12
51const ACR_P_UNKNOWN: i64 = 13
52// referee-row admission under the panel conf + receipt
53const ACR_REF_OK: i64 = 0
54const ACR_REF_NO_CONF: i64 = 1
55const ACR_REF_NO_RECEIPT: i64 = 2
56const ACR_REF_PANEL_UNADMITTED: i64 = 3
57const ACR_REF_TIER_UNADMITTED: i64 = 4
58const ACR_REF_NO_FLOOR: i64 = 5
59// exit codes of the nx_accept verbs, HERE so the gate reads them instead of mirroring them
60const ACR_EXIT_AGREED: i64 = 0
61const ACR_EXIT_NOT_AGREED: i64 = 1
62const ACR_EXIT_USAGE: i64 = 2
63const ACR_EXIT_UNKNOWN: i64 = 3
64const ACR_EXIT_REFUSED: i64 = 4
65const ACR_EXIT_IO: i64 = 5
66const ACR_EXIT_UNOBS: i64 = 6
67
68const ACR_DIGEST_BYTES: i64 = 32
69const ACR_HEXCAP: i64 = 72
70const ACR_NIB: i64 = 16
71const ACR_HEX_ALPHA: i64 = 87 // 'a' minus 10: nibbles 10..15 print as a..f
72const ACR_UNOBS: i64 = 0 - 9999 // nx_charjudge_census CJP_UNOBS: a lens that could not see
73const ACR_LINECAP: i64 = 1024
74const ACR_LP: i64 = 16
75const ACR_WHY_WORDS: i64 = 8
76const ACR_DECL_TAIL: *u8 = "() -> i64 { return 1 }"
77const ACR_FUNC_KW: *u8 = "func "
78
79func acr_catf(d: *u8, o: i64, key: *u8, v: *u8) -> i64 { var p: i64 = al_cat(d, o, key); p = al_cat(d, p, v); return p }
80func acr_catfn(d: *u8, o: i64, key: *u8, v: i64) -> i64 { var p: i64 = al_cat(d, o, key); p = al_catn(d, p, v); return p }
81
82// ---- the named party --------------------------------------------------------------------------------------
83func acr_party(bk: *i64, cf: *i64, si: i64, why: *i64) -> i64 {
84 let st: i64 = al_state(bk, cf, si, why)
85 if st == AL_ST_ACCEPTED { return ACR_P_AGREED }
86 let it: *i64 = al_bk_ints(bk, si)
87 if it[AL_I_OPSEEN] == 0 { return ACR_P_OP_MISSING }
88 if why[AL_WHY_OP] == AL_V_REJECT { return ACR_P_OP_REJECT }
89 if why[AL_WHY_OP] == AL_V_UNJUDGED { return ACR_P_OP_UNJUDGED }
90 if why[AL_WHY_OP] != AL_V_ACCEPT { return ACR_P_OP_INVALID }
91 let rc: i64 = why[AL_WHY_REF]
92 if rc == AL_RC_MISSING { return ACR_P_REF_MISSING }
93 if rc == AL_RC_BAD { return ACR_P_REF_BAD }
94 if rc == AL_RC_INVALID { return ACR_P_REF_INVALID }
95 if rc == AL_RC_PANEL_UNADMITTED { return ACR_P_REF_PANEL }
96 if rc == AL_RC_TIER_UNADMITTED { return ACR_P_REF_TIER }
97 if rc == AL_RC_NO_FLOOR { return ACR_P_REF_NOFLOOR }
98 if rc == AL_RC_BELOW_FLOOR { return ACR_P_REF_BELOW }
99 if why[AL_WHY_ATT] != 1 { return ACR_P_SEAT_MISSING }
100 return ACR_P_UNKNOWN
101}
102func acr_party_name(c: i64) -> *u8 {
103 if c == ACR_P_AGREED { return "AGREED" as *u8 }
104 if c == ACR_P_OP_MISSING { return "OPERATOR-MISSING" as *u8 }
105 if c == ACR_P_OP_REJECT { return "OPERATOR-REJECT" as *u8 }
106 if c == ACR_P_OP_UNJUDGED { return "OPERATOR-UNJUDGED" as *u8 }
107 if c == ACR_P_OP_INVALID { return "OPERATOR-INVALID-VERDICT" as *u8 }
108 if c == ACR_P_REF_MISSING { return "REFEREE-MISSING" as *u8 }
109 if c == ACR_P_REF_BAD { return "REFEREE-BAD" as *u8 }
110 if c == ACR_P_REF_INVALID { return "REFEREE-INVALID-ROW" as *u8 }
111 if c == ACR_P_REF_PANEL { return "REFEREE-PANEL-UNADMITTED" as *u8 }
112 if c == ACR_P_REF_TIER { return "REFEREE-TIER-UNADMITTED" as *u8 }
113 if c == ACR_P_REF_NOFLOOR { return "REFEREE-NO-FLOOR-FOR-TIER" as *u8 }
114 if c == ACR_P_REF_BELOW { return "REFEREE-BELOW-BAND" as *u8 }
115 if c == ACR_P_SEAT_MISSING { return "SEAT-MISSING" as *u8 }
116 return "UNKNOWN" as *u8
117}
118
119// ---- referee-row admission -----------------------------------------------------------------------------------
120func acr_ref_admit(cf: *i64, tier: *u8, floor_out: *i64) -> i64 {
121 floor_out[0] = LCF_MISS
122 if cf[AL_C_CONF_OK] == 0 { return ACR_REF_NO_CONF }
123 if cf[AL_C_RCPT_OK] == 0 { return ACR_REF_NO_RECEIPT }
124 if cf[AL_C_ADMITTED] != 1 { return ACR_REF_PANEL_UNADMITTED }
125 if al_list_has(cf[AL_C_TADM] as *u8, tier) == 0 { return ACR_REF_TIER_UNADMITTED }
126 let fl: i64 = al_floor_for_tier(cf, tier)
127 if fl == LCF_MISS { return ACR_REF_NO_FLOOR }
128 floor_out[0] = fl
129 return ACR_REF_OK
130}
131func acr_ref_admit_name(c: i64) -> *u8 {
132 if c == ACR_REF_OK { return "OK" as *u8 }
133 if c == ACR_REF_NO_CONF { return "NO-PANEL-CONF" as *u8 }
134 if c == ACR_REF_NO_RECEIPT { return "NO-ADMISSION-RECEIPT" as *u8 }
135 if c == ACR_REF_PANEL_UNADMITTED { return "PANEL-UNADMITTED" as *u8 }
136 if c == ACR_REF_TIER_UNADMITTED { return "TIER-UNADMITTED" as *u8 }
137 return "NO-FLOOR-FOR-TIER" as *u8
138}
139// GOOD iff the measured percept clears the tier floor. The row's WORD is necessary, never sufficient: the core
140// re-derives it from the same floor, so a row cannot lie its way past the bar.
141func acr_composite(percept: i64, floor: i64) -> i64 { if floor == LCF_MISS { return 0 } if percept >= floor { return 1 } return 0 }
142
143// ---- mid-line key=<int> (optional leading minus). `absent` when the key or its digits are not there. ----------
144func acr_kvint(buf: *u8, n: i64, key: *u8, absent: i64) -> i64 {
145 let kl: i64 = al_slen(key)
146 if kl == 0 { return absent }
147 var i: i64 = 0
148 while i + kl <= n {
149 var m: i64 = 1
150 var j: i64 = 0
151 while j < kl { if buf[i + j] != key[j] { m = 0; j = kl } else { j = j + 1 } }
152 if m == 1 {
153 var p: i64 = i + kl
154 var neg: i64 = 0
155 if p < n { if (buf[p] as i64) == AL_MINUS { neg = 1; p = p + 1 } }
156 var v: i64 = 0
157 var digits: i64 = 0
158 var run: i64 = 1
159 while run == 1 {
160 if p < n {
161 let c: i64 = buf[p] as i64
162 var isd: i64 = 0
163 if c >= AL_D0 { if c <= AL_D9 { isd = 1 } }
164 if isd == 1 { v = v * AL_BASE10 + (c - AL_D0); digits = digits + 1; p = p + 1 } else { run = 0 }
165 } else { run = 0 }
166 }
167 if digits == 0 { return absent }
168 if neg == 1 { return 0 - v }
169 return v
170 }
171 i = i + 1
172 }
173 return absent
174}
175
176// ---- sha256 as 64 hex, of a buffer or a file -------------------------------------------------------------------
177func acr_hex(d: *u8, out: *u8) -> i64 {
178 var i: i64 = 0
179 while i < ACR_DIGEST_BYTES {
180 let v: i64 = d[i] as i64
181 let hi: i64 = v / ACR_NIB
182 let lo: i64 = v % ACR_NIB
183 if hi < AL_BASE10 { out[i * 2] = (AL_D0 + hi) as u8 } else { out[i * 2] = (ACR_HEX_ALPHA + hi) as u8 }
184 if lo < AL_BASE10 { out[i * 2 + 1] = (AL_D0 + lo) as u8 } else { out[i * 2 + 1] = (ACR_HEX_ALPHA + lo) as u8 }
185 i = i + 1
186 }
187 out[ACR_DIGEST_BYTES * 2] = 0 as u8
188 return ACR_DIGEST_BYTES * 2
189}
190func acr_sha256_buf(b: *u8, n: i64, outhex: *u8) -> i64 {
191 let d: *u8 = sys_mmap(ACR_DIGEST_BYTES)
192 sha256_digest(b, n, d)
193 return acr_hex(d, outhex)
194}
195// -1 when the file cannot be read (outhex emptied); never the digest of nothing
196func acr_sha256_file(path: *u8, outhex: *u8) -> i64 {
197 outhex[0] = 0 as u8
198 let ln: *i64 = sys_mmap(ACR_LP) as *i64
199 let b: *u8 = sys_read_file(path, ln)
200 if (b as i64) == 0 { return 0 - 1 }
201 acr_sha256_buf(b, ln[0], outhex)
202 return ln[0]
203}
204
205// ---- the status line ----------------------------------------------------------------------------------------
206// dom/org may be 0 (no board column). Returns the new offset, -1 when the buffer cannot take another line.
207func acr_status_line(bk: *i64, cf: *i64, si: i64, dom: *u8, org: *u8, out: *u8, o0: i64, cap: i64) -> i64 {
208 if o0 + ACR_LINECAP >= cap { return 0 - 1 }
209 let why: *i64 = sys_mmap(8 * ACR_WHY_WORDS) as *i64
210 let party: i64 = acr_party(bk, cf, si, why)
211 let it: *i64 = al_bk_ints(bk, si)
212 let rec: *u8 = al_bk_rec(bk, si)
213 var o: i64 = acr_catf(out, o0, "subject=" as *u8, al_bk_name(bk, si))
214 if party == ACR_P_AGREED { o = al_cat(out, o, " verdict=AGREED" as *u8) } else { o = al_cat(out, o, " verdict=NOT-AGREED" as *u8) }
215 o = acr_catf(out, o, " missing=" as *u8, acr_party_name(party))
216 o = acr_catf(out, o, " operator=" as *u8, al_vname(why[AL_WHY_OP]))
217 o = acr_catfn(out, o, " op_rows=" as *u8, it[AL_I_OPSEEN])
218 o = acr_catf(out, o, " referee=" as *u8, al_rcname(why[AL_WHY_REF]))
219 o = acr_catfn(out, o, " ref_rows=" as *u8, it[AL_I_RSEEN])
220 if it[AL_I_RSEEN] == 0 { o = al_cat(out, o, " percept=none" as *u8) } else { o = acr_catfn(out, o, " percept=" as *u8, it[AL_I_RPERCEPT]) }
221 if why[AL_WHY_FLOOR] == LCF_MISS { o = al_cat(out, o, " floor=none" as *u8) } else { o = acr_catfn(out, o, " floor=" as *u8, why[AL_WHY_FLOOR]) }
222 let tier: *u8 = ((rec as i64) + AL_F_RTIER) as *u8
223 if tier[0] == (0 as u8) { o = al_cat(out, o, " tier=-" as *u8) } else { o = acr_catf(out, o, " tier=" as *u8, tier) }
224 o = acr_catfn(out, o, " seat=" as *u8, it[AL_I_ATT])
225 o = acr_catfn(out, o, " att_rows=" as *u8, it[AL_I_ASEEN])
226 var hasboard: i64 = 0
227 if (dom as i64) != 0 { if dom[0] != (0 as u8) { hasboard = 1 } }
228 if hasboard == 0 { o = al_cat(out, o, " board=-" as *u8) } else {
229 o = acr_catf(out, o, " board=" as *u8, dom)
230 o = acr_catf(out, o, " organ=" as *u8, org)
231 if al_streq(org, AL_DECL_ROW) == 1 { o = al_cat(out, o, " organ_row=OK" as *u8) } else { o = al_cat(out, o, " organ_row=WRONG-FILE-cannot-flip" as *u8) }
232 }
233 out[o] = AL_NL as u8
234 o = o + 1
235 out[o] = 0 as u8
236 return o
237}
238
239// ---- the summary line: every counter the book kept, so the partition is on the record ------------------------
240func acr_summary(bk: *i64, cf: *i64, planes: i64, unmapped_named: i64, out: *u8, o0: i64, cap: i64) -> i64 {
241 if o0 + ACR_LINECAP >= cap { return 0 - 1 }
242 let n: i64 = bk[AL_B_N]
243 let a: i64 = al_count_accepted(bk, cf)
244 var o: i64 = acr_catfn(out, o0, "ACCEPT-LEDGER subjects=" as *u8, n)
245 o = acr_catfn(out, o, " agreed=" as *u8, a)
246 o = acr_catfn(out, o, " not_agreed=" as *u8, n - a)
247 o = acr_catfn(out, o, " planes=" as *u8, planes)
248 o = al_cat(out, o, "/3" as *u8)
249 o = acr_catfn(out, o, " acc_rows=" as *u8, bk[AL_B_ACC_ROWS])
250 o = acr_catfn(out, o, " unmapped=" as *u8, bk[AL_B_UNMAPPED])
251 o = acr_catfn(out, o, " unmapped_named=" as *u8, unmapped_named)
252 o = acr_catfn(out, o, " ref_rows=" as *u8, bk[AL_B_REF_ROWS])
253 o = acr_catfn(out, o, " att_rows=" as *u8, bk[AL_B_ATT_ROWS])
254 o = acr_catfn(out, o, " malformed=" as *u8, bk[AL_B_MALFORMED])
255 o = acr_catfn(out, o, " badname=" as *u8, bk[AL_B_BADNAME])
256 o = acr_catfn(out, o, " tombstones=" as *u8, bk[AL_B_TOMB])
257 o = acr_catfn(out, o, " foreign_keys=" as *u8, bk[AL_B_FOREIGN])
258 o = acr_catfn(out, o, " overflow=" as *u8, bk[AL_B_OVERFLOW])
259 if bk[AL_B_OVERFLOW] > 0 { o = al_cat(out, o, " THIS-LIST-IS-A-PREFIX-book-full" as *u8) }
260 out[o] = AL_NL as u8
261 o = o + 1
262 out[o] = 0 as u8
263 return o
264}
265
266// ---- name order over the whole book (selection sort, same rule the emitter uses) --------------------------------
267func acr_order(bk: *i64, ord: *i64) -> i64 {
268 let n: i64 = bk[AL_B_N]
269 var i: i64 = 0
270 while i < n { ord[i] = i; i = i + 1 }
271 var a: i64 = 0
272 while a < n {
273 var best: i64 = a
274 var b2: i64 = a + 1
275 while b2 < n { if al_strcmp(al_bk_name(bk, ord[b2]), al_bk_name(bk, ord[best])) < 0 { best = b2 } b2 = b2 + 1 }
276 if best != a { let t: i64 = ord[a]; ord[a] = ord[best]; ord[best] = t }
277 a = a + 1
278 }
279 return n
280}
281
282// ---- UNMAPPED rows, NAMED. pfx is the RESOLVED accept plane path. oo[0] is the in/out offset. Returns the count.
283func acr_unmapped(pfx: *u8, out: *u8, oo: *i64, cap: i64) -> i64 {
284 let scratch: *i64 = al_bk_new()
285 let cur: *i64 = al_rows_open(pfx)
286 if cur[AL_RS_LEN] <= 0 { return 0 }
287 let sc: *i64 = sys_mmap(8 * AL_SC_WORDS) as *i64
288 let f: *i64 = sys_mmap(ACR_LP) as *i64
289 let idx: *i64 = sys_mmap(8 * AL_MAX_TOK) as *i64
290 var o: i64 = oo[0]
291 var cnt: i64 = 0
292 while al_rows_next(cur, sc) == 1 {
293 let v: *u8 = sc[2] as *u8
294 let vl: i64 = sc[3]
295 if cw_field(v, vl, AL_AF_TARGETS, f) == 1 {
296 let nt: i64 = al_targets_subjects(scratch, v, f[0], f[1], idx, AL_MAX_TOK)
297 if nt == 0 {
298 cnt = cnt + 1
299 if o + vl + ACR_LINECAP < cap {
300 o = al_cat(out, o, "UNMAPPED id=" as *u8)
301 if cw_field(v, vl, AL_AF_ID, f) == 1 { o = al_catsl(out, o, v, f[0], f[1]) }
302 o = al_cat(out, o, " verdict=" as *u8)
303 if cw_field(v, vl, AL_AF_VERDICT, f) == 1 { o = al_catsl(out, o, v, f[0], f[1]) }
304 o = al_cat(out, o, " actor=" as *u8)
305 if cw_field(v, vl, AL_AF_ACTOR, f) == 1 { o = al_catsl(out, o, v, f[0], f[1]) }
306 o = al_cat(out, o, " targets=" as *u8)
307 if cw_field(v, vl, AL_AF_TARGETS, f) == 1 { o = al_catsl(out, o, v, f[0], f[1]) }
308 o = al_cat(out, o, " governs=NOTHING remedy=re-file the verdict with targets carrying ga_accept_<subject>" as *u8)
309 out[o] = AL_NL as u8
310 o = o + 1
311 }
312 }
313 }
314 }
315 out[o] = 0 as u8
316 oo[0] = o
317 return cnt
318}
319
320// ---- board subjects into the book; doms/orgs are per-BOOK-INDEX tables (AL_NAMEW / AL_ORGW wide, zeroed by the
321// caller). Returns the number of board rows, -1 when dir is unreadable, and over[0] counts rows past the cap.
322func acr_boards(bk: *i64, dir: *u8, doms: *u8, orgs: *u8, over: *i64) -> i64 {
323 let sj: *u8 = sys_mmap(AL_NAMEW * AL_MAX_WATCH)
324 let sd: *u8 = sys_mmap(AL_NAMEW * AL_MAX_WATCH)
325 let so: *u8 = sys_mmap(AL_ORGW * AL_MAX_WATCH)
326 let n: i64 = al_scan_boards(dir, sj, sd, so, AL_MAX_WATCH, over)
327 if n < 0 { return n }
328 var i: i64 = 0
329 while i < n {
330 let nm: *u8 = ((sj as i64) + i * AL_NAMEW) as *u8
331 let dm: *u8 = ((sd as i64) + i * AL_NAMEW) as *u8
332 let og: *u8 = ((so as i64) + i * AL_ORGW) as *u8
333 let si: i64 = al_bk_get(bk, nm, 0, al_slen(nm))
334 if si >= 0 {
335 al_setf(doms, si * AL_NAMEW, AL_NAMEW, dm, 0, al_slen(dm))
336 al_setf(orgs, si * AL_ORGW, AL_ORGW, og, 0, al_slen(og))
337 }
338 i = i + 1
339 }
340 return n
341}
342
343// ---- the emitted file's shape ruler ----------------------------------------------------------------------------
344// count of lines beginning with needle (column 0)
345func acr_lines_starting(b: *u8, n: i64, needle: *u8) -> i64 {
346 let nl: i64 = al_slen(needle)
347 var cnt: i64 = 0
348 var i: i64 = 0
349 while i + nl <= n {
350 var bol: i64 = 0
351 if i == 0 { bol = 1 } else { if (b[i - 1] as i64) == AL_NL { bol = 1 } }
352 if bol == 1 {
353 var m: i64 = 1
354 var j: i64 = 0
355 while j < nl { if b[i + j] != needle[j] { m = 0; j = nl } else { j = j + 1 } }
356 if m == 1 { cnt = cnt + 1 }
357 }
358 i = i + 1
359 }
360 return cnt
361}
362// does the buffer declare ga_accept_<subject> (column-0 func, exact identifier)?
363func acr_declares(b: *u8, n: i64, subject: *u8) -> i64 {
364 let needle: *u8 = sys_mmap(AL_KEYCAP)
365 var o: i64 = al_cat(needle, 0, ACR_FUNC_KW)
366 o = al_cat(needle, o, AL_SYM_PFX)
367 o = al_cat(needle, o, subject)
368 o = al_cat(needle, o, "(" as *u8)
369 needle[o] = 0 as u8
370 if acr_lines_starting(b, n, needle) > 0 { return 1 }
371 return 0
372}
373// -1 on the first line that is neither a comment, blank, nor the ONE permitted declaration form; else the count
374func acr_decl_shape(b: *u8, n: i64) -> i64 {
375 let kw: *u8 = ACR_FUNC_KW
376 let kl: i64 = al_slen(kw)
377 let pl: i64 = al_slen(AL_SYM_PFX)
378 let tl: i64 = al_slen(ACR_DECL_TAIL)
379 var cnt: i64 = 0
380 var p: i64 = 0
381 while p < n {
382 var e: i64 = p
383 while e < n { if (b[e] as i64) == AL_NL { break } e = e + 1 }
384 let len: i64 = e - p
385 if len > 0 {
386 var comment: i64 = 0
387 if len >= 2 { if (b[p] as i64) == AL_SLASH { if (b[p + 1] as i64) == AL_SLASH { comment = 1 } } }
388 if comment == 0 {
389 if len < kl + pl + 1 + tl { return 0 - 1 }
390 var j: i64 = 0
391 while j < kl { if b[p + j] != kw[j] { return 0 - 1 } j = j + 1 }
392 j = 0
393 while j < pl { if b[p + kl + j] != AL_SYM_PFX[j] { return 0 - 1 } j = j + 1 }
394 var k: i64 = p + kl + pl
395 let ks: i64 = k
396 while k < e { if al_ident_char(b[k] as i64) == 1 { k = k + 1 } else { break } }
397 if al_ident_ok(b, ks, k - ks) == 0 { return 0 - 1 }
398 if e - k != tl { return 0 - 1 }
399 j = 0
400 while j < tl { if b[k + j] != ACR_DECL_TAIL[j] { return 0 - 1 } j = j + 1 }
401 cnt = cnt + 1
402 }
403 }
404 p = e + 1
405 }
406 return cnt
407}