nx_varcensus_lib.nx source
↩ module page · 594 lines · 24713 B
1// nx_varcensus_lib.nx -- the VaM corpus census's DATA-DRIVEN pieces, importable by the CLI (nx_varcensus) and its gate.
2//
3// (1) a growable byte ARENA -- tables store OFFSETS into it, so growth (a bigger mapping plus a copy) never leaves a
4// dangling pointer; an i64 vector rides the same arena in 8-byte cells.
5// (2) a growable string COUNTER -- FNV-1a, open addressing, the slot table doubled at half load; entries are kept in
6// FIRST-SEEN ORDER so a report reads in the order the corpus was walked (and the walk itself is sorted).
7// (3) the RULES conf (the classifier is DATA, never code). Rows, TAB separated, '#' comments:
8// role|format <TAB> <class> <TAB> <kind> <TAB> <pattern> [<TAB> <kind> <TAB> <pattern>] both conditions must hold
9// screen <TAB> <reason letter A-Z> <TAB> class <TAB> <role class> a member of that class sets the reason
10// screen <TAB> <reason letter A-Z> <TAB> namecontains <TAB> <token> the package id contains the token
11// deptag <TAB> <tag> <TAB> prefix <TAB> <dependency id prefix> a direct dependency with that prefix
12// kinds: dirent (name ends with a slash) | exact | prefix | suffix | contains. Matching is on LOWERCASED names and
13// lowercased patterns. Within one axis the FIRST matching rule wins, and a member no rule matches lands in the implicit
14// class `other` of that axis -- so each axis is a PARTITION of the members by construction, and the census asserts the
15// sum. A row this parser does not understand is an ERROR counted with its line number: a malformed rules file cannot
16// produce a census (the CLI refuses), because a silently skipped rule moves members into `other` with no trace.
17// license_tier: ORIGINAL No hw writes (Rule 26).
18import "nx_syscalls.nx"
19
20const VCL_PAD: i64 = 16
21const VCL_ARENA_INIT: i64 = 65536
22const VCL_CELL: i64 = 8
23const VCL_A_PTR: i64 = 0
24const VCL_A_USED: i64 = 1
25const VCL_A_CAP: i64 = 2
26const VCL_A_N: i64 = 3
27
28const VCL_TAB: i64 = 9
29const VCL_LF: i64 = 10
30const VCL_CR: i64 = 13
31const VCL_SPACE: i64 = 32
32const VCL_HASHMARK: i64 = 35
33const VCL_SLASH: i64 = 47
34const VCL_DOT: i64 = 46
35const VCL_UPPER_A: i64 = 65
36const VCL_UPPER_Z: i64 = 90
37const VCL_CASE_OFF: i64 = 32
38const VCL_ASCII_0: i64 = 48
39const VCL_DEC: i64 = 10
40
41// counter
42const VCL_FNV_BASIS: i64 = 2166136261
43const VCL_FNV_PRIME: i64 = 16777619
44const VCL_U32_MASK: i64 = 0xffffffff
45const VCL_SLOTS_INIT: i64 = 256
46const VCL_E_W: i64 = 4
47const VCL_E_HASH: i64 = 0
48const VCL_E_KOFF: i64 = 1
49const VCL_E_KLEN: i64 = 2
50const VCL_E_COUNT: i64 = 3
51const VCL_C_SLOTS: i64 = 0
52const VCL_C_CAP: i64 = 1
53const VCL_C_NENT: i64 = 2
54const VCL_C_ENTS: i64 = 3
55const VCL_C_KEYS: i64 = 4
56const VCL_C_N: i64 = 5
57
58// rules
59const VCL_K_NONE: i64 = 0
60const VCL_K_DIRENT: i64 = 1
61const VCL_K_EXACT: i64 = 2
62const VCL_K_PREFIX: i64 = 3
63const VCL_K_SUFFIX: i64 = 4
64const VCL_K_CONTAINS: i64 = 5
65const VCL_AX_ROLE: i64 = 0
66const VCL_AX_FORMAT: i64 = 1
67const VCL_AX_N: i64 = 2
68const VCL_R_W: i64 = 8
69const VCL_R_AXIS: i64 = 0
70const VCL_R_CLASS: i64 = 1
71const VCL_R_K1: i64 = 2
72const VCL_R_P1: i64 = 3
73const VCL_R_L1: i64 = 4
74const VCL_R_K2: i64 = 5
75const VCL_R_P2: i64 = 6
76const VCL_R_L2: i64 = 7
77const VCL_S_W: i64 = 4
78const VCL_S_BIT: i64 = 0
79const VCL_S_KIND: i64 = 1
80const VCL_S_ARG: i64 = 2
81const VCL_S_LEN: i64 = 3
82const VCL_SK_CLASS: i64 = 1
83const VCL_SK_NAME: i64 = 2
84const VCL_T_W: i64 = 3
85const VCL_T_TAG: i64 = 0
86const VCL_T_P: i64 = 1
87const VCL_T_L: i64 = 2
88const VCL_REASONS: i64 = 26
89const VCL_MAX_FIELDS: i64 = 8
90// rules box
91const VCL_RS_RULES: i64 = 0
92const VCL_RS_NRULES: i64 = 1
93const VCL_RS_STR: i64 = 2
94const VCL_RS_CLASS_ROLE: i64 = 3
95const VCL_RS_CLASS_FORMAT: i64 = 4
96const VCL_RS_OTHER_ROLE: i64 = 5
97const VCL_RS_OTHER_FORMAT: i64 = 6
98const VCL_RS_SCREEN: i64 = 7
99const VCL_RS_NSCREEN: i64 = 8
100const VCL_RS_DEPTAG: i64 = 9
101const VCL_RS_NDEPTAG: i64 = 10
102const VCL_RS_TAGS: i64 = 11
103const VCL_RS_ERRORS: i64 = 12
104const VCL_RS_FIRST_ERR_LINE: i64 = 13
105const VCL_RS_N: i64 = 16
106const VCL_OTHER: *u8 = "other"
107
108func vcl_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
109func vcl_lc(c: i64) -> i64 { if c >= VCL_UPPER_A { if c <= VCL_UPPER_Z { return c + VCL_CASE_OFF } } return c }
110func vcl_lower(src: *u8, n: i64, out: *u8) -> i64 {
111 var i: i64 = 0
112 while i < n { out[i] = vcl_lc(src[i] as i64 & 0xff) as u8; i = i + 1 }
113 out[n] = 0 as u8
114 return n
115}
116func vcl_eq(a: *u8, ao: i64, b: *u8, bo: i64, n: i64) -> i64 {
117 var i: i64 = 0
118 while i < n { if (a[ao+i] as i64 & 0xff) != (b[bo+i] as i64 & 0xff) { return 0 } i = i + 1 }
119 return 1
120}
121
122// ---- (1) ARENA ----
123func vcl_arena_new(init: i64) -> *i64 {
124 let a: *i64 = sys_mmap(VCL_A_N * VCL_CELL) as *i64
125 var cap: i64 = init
126 if cap < VCL_ARENA_INIT { cap = VCL_ARENA_INIT }
127 a[VCL_A_PTR] = sys_mmap(cap + VCL_PAD) as i64
128 a[VCL_A_USED] = 0
129 a[VCL_A_CAP] = cap
130 return a
131}
132func vcl_arena_reserve(a: *i64, extra: i64) -> i64 {
133 let need: i64 = a[VCL_A_USED] + extra
134 if need <= a[VCL_A_CAP] { return 1 }
135 var ncap: i64 = a[VCL_A_CAP] * 2
136 while ncap < need { ncap = ncap * 2 }
137 let nb: *u8 = sys_mmap(ncap + VCL_PAD)
138 if (nb as i64) <= 0 { return 0 }
139 let ob: *u8 = a[VCL_A_PTR] as *u8
140 let used: i64 = a[VCL_A_USED]
141 var i: i64 = 0
142 while i < used { nb[i] = ob[i]; i = i + 1 }
143 sys_munmap(ob, a[VCL_A_CAP] + VCL_PAD)
144 a[VCL_A_PTR] = nb as i64
145 a[VCL_A_CAP] = ncap
146 return 1
147}
148func vcl_at(a: *i64, off: i64) -> *u8 { return (a[VCL_A_PTR] + off) as *u8 }
149func vcl_used(a: *i64) -> i64 { return a[VCL_A_USED] }
150// store n bytes plus a NUL; returns the offset or -1
151func vcl_put(a: *i64, src: *u8, so: i64, n: i64) -> i64 {
152 if vcl_arena_reserve(a, n + 1) == 0 { return 0 - 1 }
153 let b: *u8 = a[VCL_A_PTR] as *u8
154 let off: i64 = a[VCL_A_USED]
155 var i: i64 = 0
156 while i < n { b[off+i] = src[so+i]; i = i + 1 }
157 b[off+n] = 0 as u8
158 a[VCL_A_USED] = off + n + 1
159 return off
160}
161// text appenders (no terminator): bytes, a NUL-terminated string, one byte, a decimal, TSV-clean bytes
162func vcl_app(a: *i64, src: *u8, so: i64, n: i64) -> i64 {
163 if vcl_arena_reserve(a, n) == 0 { return 0 }
164 let b: *u8 = a[VCL_A_PTR] as *u8
165 let off: i64 = a[VCL_A_USED]
166 var i: i64 = 0
167 while i < n { b[off+i] = src[so+i]; i = i + 1 }
168 a[VCL_A_USED] = off + n
169 return 1
170}
171func vcl_apps(a: *i64, s: *u8) -> i64 { return vcl_app(a, s, 0, vcl_slen(s)) }
172func vcl_appc(a: *i64, c: i64) -> i64 {
173 if vcl_arena_reserve(a, 1) == 0 { return 0 }
174 let b: *u8 = a[VCL_A_PTR] as *u8
175 b[a[VCL_A_USED]] = c as u8
176 a[VCL_A_USED] = a[VCL_A_USED] + 1
177 return 1
178}
179func vcl_appn(a: *i64, v: i64) -> i64 {
180 if vcl_arena_reserve(a, 24) == 0 { return 0 }
181 let b: *u8 = a[VCL_A_PTR] as *u8
182 var p: i64 = a[VCL_A_USED]
183 var m: i64 = v
184 if m < 0 { b[p] = 45 as u8; p = p + 1; m = 0 - m }
185 if m == 0 { b[p] = VCL_ASCII_0 as u8; a[VCL_A_USED] = p + 1; return 1 }
186 let s: i64 = p
187 while m > 0 { b[p] = (VCL_ASCII_0 + (m % VCL_DEC)) as u8; m = m / VCL_DEC; p = p + 1 }
188 var i: i64 = s
189 var j: i64 = p - 1
190 while i < j { let t: u8 = b[i]; b[i] = b[j]; b[j] = t; i = i + 1; j = j - 1 }
191 a[VCL_A_USED] = p
192 return 1
193}
194// TSV-clean: TAB, CR, LF and every control byte become a space, so a value can never open a column or a row
195func vcl_appclean(a: *i64, src: *u8, so: i64, n: i64) -> i64 {
196 if vcl_arena_reserve(a, n) == 0 { return 0 }
197 let b: *u8 = a[VCL_A_PTR] as *u8
198 let off: i64 = a[VCL_A_USED]
199 var i: i64 = 0
200 while i < n {
201 let c: i64 = src[so+i] as i64 & 0xff
202 if c < VCL_SPACE { b[off+i] = VCL_SPACE as u8 } else { b[off+i] = c as u8 }
203 i = i + 1
204 }
205 a[VCL_A_USED] = off + n
206 return 1
207}
208func vcl_push(a: *i64, v: i64) -> i64 {
209 if vcl_arena_reserve(a, VCL_CELL) == 0 { return 0 }
210 let cell: *i64 = (a[VCL_A_PTR] + a[VCL_A_USED]) as *i64
211 cell[0] = v
212 a[VCL_A_USED] = a[VCL_A_USED] + VCL_CELL
213 return 1
214}
215func vcl_vec_n(a: *i64) -> i64 { return a[VCL_A_USED] / VCL_CELL }
216func vcl_vec_at(a: *i64, i: i64) -> i64 { let cell: *i64 = (a[VCL_A_PTR] + i * VCL_CELL) as *i64; return cell[0] }
217
218// ---- (2) COUNTER ----
219func vcl_hash(s: *u8, so: i64, n: i64) -> i64 {
220 var h: i64 = VCL_FNV_BASIS
221 var i: i64 = 0
222 while i < n {
223 h = h ^ (s[so+i] as i64 & 0xff)
224 h = (h * VCL_FNV_PRIME) & VCL_U32_MASK
225 i = i + 1
226 }
227 return h
228}
229func vcl_counter_new() -> *i64 {
230 let c: *i64 = sys_mmap(VCL_C_N * VCL_CELL) as *i64
231 c[VCL_C_SLOTS] = sys_mmap(VCL_SLOTS_INIT * VCL_CELL) as i64
232 c[VCL_C_CAP] = VCL_SLOTS_INIT
233 c[VCL_C_NENT] = 0
234 c[VCL_C_ENTS] = vcl_arena_new(VCL_ARENA_INIT) as i64
235 c[VCL_C_KEYS] = vcl_arena_new(VCL_ARENA_INIT) as i64
236 return c
237}
238func vcl_ent(c: *i64, idx: i64) -> *i64 {
239 let ents: *i64 = c[VCL_C_ENTS] as *i64
240 return (ents[VCL_A_PTR] + idx * VCL_E_W * VCL_CELL) as *i64
241}
242func vcl_counter_n(c: *i64) -> i64 { return c[VCL_C_NENT] }
243func vcl_counter_count(c: *i64, idx: i64) -> i64 { let e: *i64 = vcl_ent(c, idx); return e[VCL_E_COUNT] }
244func vcl_counter_key(c: *i64, idx: i64) -> *u8 { let e: *i64 = vcl_ent(c, idx); return vcl_at(c[VCL_C_KEYS] as *i64, e[VCL_E_KOFF]) }
245func vcl_counter_klen(c: *i64, idx: i64) -> i64 { let e: *i64 = vcl_ent(c, idx); return e[VCL_E_KLEN] }
246func vcl_counter_rehash(c: *i64, ncap: i64) -> i64 {
247 let ns: *i64 = sys_mmap(ncap * VCL_CELL) as *i64
248 if (ns as i64) <= 0 { return 0 }
249 let mask: i64 = ncap - 1
250 var k: i64 = 0
251 while k < c[VCL_C_NENT] {
252 let e: *i64 = vcl_ent(c, k)
253 var i: i64 = e[VCL_E_HASH] & mask
254 var run: i64 = 1
255 while run == 1 { if ns[i] == 0 { ns[i] = k + 1; run = 0 } else { i = (i + 1) & mask } }
256 k = k + 1
257 }
258 sys_munmap(c[VCL_C_SLOTS] as *u8, c[VCL_C_CAP] * VCL_CELL)
259 c[VCL_C_SLOTS] = ns as i64
260 c[VCL_C_CAP] = ncap
261 return 1
262}
263// add inc to key src[so..so+n); returns the entry index (first-seen order) or -1
264func vcl_counter_add(c: *i64, src: *u8, so: i64, n: i64, inc: i64) -> i64 {
265 let h: i64 = vcl_hash(src, so, n)
266 let slots: *i64 = c[VCL_C_SLOTS] as *i64
267 let mask: i64 = c[VCL_C_CAP] - 1
268 let keys: *i64 = c[VCL_C_KEYS] as *i64
269 var i: i64 = h & mask
270 var run: i64 = 1
271 while run == 1 {
272 let s: i64 = slots[i]
273 if s == 0 { run = 0 } else {
274 let e: *i64 = vcl_ent(c, s - 1)
275 if e[VCL_E_HASH] == h { if e[VCL_E_KLEN] == n { if vcl_eq(vcl_at(keys, e[VCL_E_KOFF]), 0, src, so, n) == 1 {
276 e[VCL_E_COUNT] = e[VCL_E_COUNT] + inc
277 return s - 1
278 } } }
279 i = (i + 1) & mask
280 }
281 }
282 let koff: i64 = vcl_put(keys, src, so, n)
283 if koff < 0 { return 0 - 1 }
284 let ents: *i64 = c[VCL_C_ENTS] as *i64
285 if vcl_push(ents, h) == 0 { return 0 - 1 }
286 vcl_push(ents, koff)
287 vcl_push(ents, n)
288 vcl_push(ents, inc)
289 let idx: i64 = c[VCL_C_NENT]
290 slots[i] = idx + 1
291 c[VCL_C_NENT] = idx + 1
292 if (idx + 1) * 2 > c[VCL_C_CAP] { vcl_counter_rehash(c, c[VCL_C_CAP] * 2) }
293 return idx
294}
295// index of key without adding, or -1
296func vcl_counter_find(c: *i64, src: *u8, so: i64, n: i64) -> i64 {
297 let h: i64 = vcl_hash(src, so, n)
298 let slots: *i64 = c[VCL_C_SLOTS] as *i64
299 let mask: i64 = c[VCL_C_CAP] - 1
300 let keys: *i64 = c[VCL_C_KEYS] as *i64
301 var i: i64 = h & mask
302 var run: i64 = 1
303 while run == 1 {
304 let s: i64 = slots[i]
305 if s == 0 { run = 0 } else {
306 let e: *i64 = vcl_ent(c, s - 1)
307 if e[VCL_E_HASH] == h { if e[VCL_E_KLEN] == n { if vcl_eq(vcl_at(keys, e[VCL_E_KOFF]), 0, src, so, n) == 1 { return s - 1 } } }
308 i = (i + 1) & mask
309 }
310 }
311 return 0 - 1
312}
313
314// ---- (3) RULES ----
315func vcl_kind(src: *u8, so: i64, n: i64) -> i64 {
316 let lit: *u8 = sys_mmap(n + 1)
317 vcl_lower(((src as i64) + so) as *u8, n, lit)
318 if n == 6 { if vcl_eq(lit, 0, "dirent" as *u8, 0, 6) == 1 { return VCL_K_DIRENT } }
319 if n == 5 { if vcl_eq(lit, 0, "exact" as *u8, 0, 5) == 1 { return VCL_K_EXACT } }
320 if n == 6 { if vcl_eq(lit, 0, "prefix" as *u8, 0, 6) == 1 { return VCL_K_PREFIX } }
321 if n == 6 { if vcl_eq(lit, 0, "suffix" as *u8, 0, 6) == 1 { return VCL_K_SUFFIX } }
322 if n == 8 { if vcl_eq(lit, 0, "contains" as *u8, 0, 8) == 1 { return VCL_K_CONTAINS } }
323 return VCL_K_NONE
324}
325func vcl_field_is(src: *u8, so: i64, n: i64, lit: *u8) -> i64 {
326 if vcl_slen(lit) != n { return 0 }
327 return vcl_eq(src, so, lit, 0, n)
328}
329// store a lowercased copy of src[so..so+n) in the strings arena; returns its offset
330func vcl_put_lower(str: *i64, src: *u8, so: i64, n: i64) -> i64 {
331 let tmp: *u8 = sys_mmap(n + 1)
332 vcl_lower(((src as i64) + so) as *u8, n, tmp)
333 return vcl_put(str, tmp, 0, n)
334}
335func vcl_rules_err(rs: *i64, line: i64) -> i64 {
336 if rs[VCL_RS_ERRORS] == 0 { rs[VCL_RS_FIRST_ERR_LINE] = line }
337 rs[VCL_RS_ERRORS] = rs[VCL_RS_ERRORS] + 1
338 return 0
339}
340
341// parse the rules text; returns the rules box (check VCL_RS_ERRORS before use)
342func vcl_rules_parse(text: *u8, n: i64) -> *i64 {
343 let rs: *i64 = sys_mmap(VCL_RS_N * VCL_CELL) as *i64
344 rs[VCL_RS_RULES] = vcl_arena_new(VCL_ARENA_INIT) as i64
345 rs[VCL_RS_NRULES] = 0
346 rs[VCL_RS_STR] = vcl_arena_new(VCL_ARENA_INIT) as i64
347 rs[VCL_RS_CLASS_ROLE] = vcl_counter_new() as i64
348 rs[VCL_RS_CLASS_FORMAT] = vcl_counter_new() as i64
349 rs[VCL_RS_SCREEN] = vcl_arena_new(VCL_ARENA_INIT) as i64
350 rs[VCL_RS_NSCREEN] = 0
351 rs[VCL_RS_DEPTAG] = vcl_arena_new(VCL_ARENA_INIT) as i64
352 rs[VCL_RS_NDEPTAG] = 0
353 rs[VCL_RS_TAGS] = vcl_counter_new() as i64
354 rs[VCL_RS_ERRORS] = 0
355 rs[VCL_RS_FIRST_ERR_LINE] = 0
356 let rules: *i64 = rs[VCL_RS_RULES] as *i64
357 let str: *i64 = rs[VCL_RS_STR] as *i64
358 let fs: *i64 = sys_mmap(VCL_MAX_FIELDS * VCL_CELL) as *i64
359 let fl: *i64 = sys_mmap(VCL_MAX_FIELDS * VCL_CELL) as *i64
360 // screen rows naming a class are resolved AFTER every class row is read, so row order in the file cannot matter
361 let pend: *i64 = vcl_arena_new(VCL_ARENA_INIT)
362 var line: i64 = 0
363 var p: i64 = 0
364 while p < n {
365 var q: i64 = p
366 var qrun: i64 = 1
367 while qrun == 1 { if q >= n { qrun = 0 } else { if (text[q] as i64 & 0xff) == VCL_LF { qrun = 0 } else { q = q + 1 } } }
368 var e: i64 = q
369 if e > n { e = n }
370 var ee: i64 = e
371 if ee > p { if (text[ee-1] as i64 & 0xff) == VCL_CR { ee = ee - 1 } }
372 line = line + 1
373 var skip: i64 = 0
374 if ee <= p { skip = 1 } else { if (text[p] as i64 & 0xff) == VCL_HASHMARK { skip = 1 } }
375 if skip == 0 {
376 var nf: i64 = 0
377 var s: i64 = p
378 var k: i64 = p
379 while k <= ee {
380 var at_end: i64 = 0
381 if k == ee { at_end = 1 } else { if (text[k] as i64 & 0xff) == VCL_TAB { at_end = 1 } }
382 if at_end == 1 {
383 if nf < VCL_MAX_FIELDS { fs[nf] = s; fl[nf] = k - s }
384 nf = nf + 1
385 s = k + 1
386 }
387 k = k + 1
388 }
389 var axis: i64 = 0 - 1
390 if vcl_field_is(text, fs[0], fl[0], "role" as *u8) == 1 { axis = VCL_AX_ROLE }
391 if vcl_field_is(text, fs[0], fl[0], "format" as *u8) == 1 { axis = VCL_AX_FORMAT }
392 if axis >= 0 {
393 var ok: i64 = 1
394 if nf != 4 { if nf != 6 { ok = 0 } }
395 if nf > VCL_MAX_FIELDS { ok = 0 }
396 if ok == 1 {
397 let k1: i64 = vcl_kind(text, fs[2], fl[2])
398 var k2: i64 = VCL_K_NONE
399 if nf == 6 { k2 = vcl_kind(text, fs[4], fl[4]); if k2 == VCL_K_NONE { ok = 0 } }
400 if k1 == VCL_K_NONE { ok = 0 }
401 if fl[1] <= 0 { ok = 0 }
402 if ok == 1 {
403 var cc: *i64 = rs[VCL_RS_CLASS_ROLE] as *i64
404 if axis == VCL_AX_FORMAT { cc = rs[VCL_RS_CLASS_FORMAT] as *i64 }
405 let cls: i64 = vcl_counter_add(cc, text, fs[1], fl[1], 0)
406 vcl_push(rules, axis)
407 vcl_push(rules, cls)
408 vcl_push(rules, k1)
409 vcl_push(rules, vcl_put_lower(str, text, fs[3], fl[3]))
410 vcl_push(rules, fl[3])
411 vcl_push(rules, k2)
412 if nf == 6 {
413 vcl_push(rules, vcl_put_lower(str, text, fs[5], fl[5]))
414 vcl_push(rules, fl[5])
415 } else { vcl_push(rules, 0 - 1); vcl_push(rules, 0) }
416 rs[VCL_RS_NRULES] = rs[VCL_RS_NRULES] + 1
417 }
418 }
419 if ok == 0 { vcl_rules_err(rs, line) }
420 } else {
421 if vcl_field_is(text, fs[0], fl[0], "screen" as *u8) == 1 {
422 var ok2: i64 = 1
423 if nf != 4 { ok2 = 0 }
424 var bit: i64 = 0 - 1
425 if ok2 == 1 {
426 if fl[1] != 1 { ok2 = 0 } else {
427 let letter: i64 = text[fs[1]] as i64 & 0xff
428 if letter >= VCL_UPPER_A { if letter <= VCL_UPPER_Z { bit = letter - VCL_UPPER_A } }
429 if bit < 0 { ok2 = 0 }
430 }
431 }
432 if ok2 == 1 {
433 if vcl_field_is(text, fs[2], fl[2], "class" as *u8) == 1 {
434 vcl_push(pend, bit)
435 vcl_push(pend, fs[3])
436 vcl_push(pend, fl[3])
437 vcl_push(pend, line)
438 } else {
439 if vcl_field_is(text, fs[2], fl[2], "namecontains" as *u8) == 1 {
440 let sc: *i64 = rs[VCL_RS_SCREEN] as *i64
441 vcl_push(sc, bit)
442 vcl_push(sc, VCL_SK_NAME)
443 vcl_push(sc, vcl_put_lower(str, text, fs[3], fl[3]))
444 vcl_push(sc, fl[3])
445 rs[VCL_RS_NSCREEN] = rs[VCL_RS_NSCREEN] + 1
446 } else { ok2 = 0 }
447 }
448 }
449 if ok2 == 0 { vcl_rules_err(rs, line) }
450 } else {
451 if vcl_field_is(text, fs[0], fl[0], "deptag" as *u8) == 1 {
452 var ok3: i64 = 1
453 if nf != 4 { ok3 = 0 }
454 if ok3 == 1 { if vcl_field_is(text, fs[2], fl[2], "prefix" as *u8) == 0 { ok3 = 0 } }
455 if ok3 == 1 {
456 let tg: *i64 = rs[VCL_RS_DEPTAG] as *i64
457 let tag: i64 = vcl_counter_add(rs[VCL_RS_TAGS] as *i64, text, fs[1], fl[1], 0)
458 vcl_push(tg, tag)
459 vcl_push(tg, vcl_put_lower(str, text, fs[3], fl[3]))
460 vcl_push(tg, fl[3])
461 rs[VCL_RS_NDEPTAG] = rs[VCL_RS_NDEPTAG] + 1
462 }
463 if ok3 == 0 { vcl_rules_err(rs, line) }
464 } else { vcl_rules_err(rs, line) }
465 }
466 }
467 }
468 p = e + 1
469 }
470 // the implicit `other` class of each axis
471 rs[VCL_RS_OTHER_ROLE] = vcl_counter_add(rs[VCL_RS_CLASS_ROLE] as *i64, VCL_OTHER, 0, vcl_slen(VCL_OTHER), 0)
472 rs[VCL_RS_OTHER_FORMAT] = vcl_counter_add(rs[VCL_RS_CLASS_FORMAT] as *i64, VCL_OTHER, 0, vcl_slen(VCL_OTHER), 0)
473 // resolve screen rows that name a role class
474 let npend: i64 = vcl_vec_n(pend) / VCL_S_W
475 var pi: i64 = 0
476 while pi < npend {
477 let pb: i64 = vcl_vec_at(pend, pi * VCL_S_W)
478 let po: i64 = vcl_vec_at(pend, pi * VCL_S_W + 1)
479 let pl: i64 = vcl_vec_at(pend, pi * VCL_S_W + 2)
480 let pln: i64 = vcl_vec_at(pend, pi * VCL_S_W + 3)
481 let ci: i64 = vcl_counter_find(rs[VCL_RS_CLASS_ROLE] as *i64, text, po, pl)
482 if ci < 0 { vcl_rules_err(rs, pln) } else {
483 let sc2: *i64 = rs[VCL_RS_SCREEN] as *i64
484 vcl_push(sc2, pb)
485 vcl_push(sc2, VCL_SK_CLASS)
486 vcl_push(sc2, ci)
487 vcl_push(sc2, 0)
488 rs[VCL_RS_NSCREEN] = rs[VCL_RS_NSCREEN] + 1
489 }
490 pi = pi + 1
491 }
492 return rs
493}
494
495func vcl_nclasses(rs: *i64, axis: i64) -> i64 {
496 if axis == VCL_AX_ROLE { return vcl_counter_n(rs[VCL_RS_CLASS_ROLE] as *i64) }
497 return vcl_counter_n(rs[VCL_RS_CLASS_FORMAT] as *i64)
498}
499func vcl_class_name(rs: *i64, axis: i64, idx: i64) -> *u8 {
500 if axis == VCL_AX_ROLE { return vcl_counter_key(rs[VCL_RS_CLASS_ROLE] as *i64, idx) }
501 return vcl_counter_key(rs[VCL_RS_CLASS_FORMAT] as *i64, idx)
502}
503
504// does lowercased name[0..nl) satisfy (kind, pattern)?
505func vcl_match(kind: i64, name: *u8, nl: i64, pat: *u8, pl: i64) -> i64 {
506 if kind == VCL_K_DIRENT { if nl > 0 { if (name[nl-1] as i64 & 0xff) == VCL_SLASH { return 1 } } return 0 }
507 if kind == VCL_K_EXACT { if nl != pl { return 0 } return vcl_eq(name, 0, pat, 0, pl) }
508 if kind == VCL_K_PREFIX { if nl < pl { return 0 } return vcl_eq(name, 0, pat, 0, pl) }
509 if kind == VCL_K_SUFFIX { if nl < pl { return 0 } return vcl_eq(name, nl - pl, pat, 0, pl) }
510 if kind == VCL_K_CONTAINS {
511 if pl == 0 { return 1 }
512 var i: i64 = 0
513 while i + pl <= nl { if vcl_eq(name, i, pat, 0, pl) == 1 { return 1 } i = i + 1 }
514 return 0
515 }
516 return 0
517}
518
519// the class of a lowercased member name on one axis: the first matching rule of that axis, else `other`
520func vcl_classify(rs: *i64, axis: i64, name: *u8, nl: i64) -> i64 {
521 let rules: *i64 = rs[VCL_RS_RULES] as *i64
522 let str: *i64 = rs[VCL_RS_STR] as *i64
523 let nr: i64 = rs[VCL_RS_NRULES]
524 var r: i64 = 0
525 while r < nr {
526 let base: i64 = r * VCL_R_W
527 if vcl_vec_at(rules, base + VCL_R_AXIS) == axis {
528 let k1: i64 = vcl_vec_at(rules, base + VCL_R_K1)
529 if vcl_match(k1, name, nl, vcl_at(str, vcl_vec_at(rules, base + VCL_R_P1)), vcl_vec_at(rules, base + VCL_R_L1)) == 1 {
530 let k2: i64 = vcl_vec_at(rules, base + VCL_R_K2)
531 var both: i64 = 1
532 if k2 != VCL_K_NONE {
533 both = vcl_match(k2, name, nl, vcl_at(str, vcl_vec_at(rules, base + VCL_R_P2)), vcl_vec_at(rules, base + VCL_R_L2))
534 }
535 if both == 1 { return vcl_vec_at(rules, base + VCL_R_CLASS) }
536 }
537 }
538 r = r + 1
539 }
540 if axis == VCL_AX_ROLE { return rs[VCL_RS_OTHER_ROLE] }
541 return rs[VCL_RS_OTHER_FORMAT]
542}
543
544// the real-person-screen reason bitmask of one package: role class counts (index = role class) plus the lowercased id
545func vcl_screen(rs: *i64, role_counts: *i64, id_lc: *u8, idl: i64) -> i64 {
546 let sc: *i64 = rs[VCL_RS_SCREEN] as *i64
547 let str: *i64 = rs[VCL_RS_STR] as *i64
548 var mask: i64 = 0
549 var i: i64 = 0
550 while i < rs[VCL_RS_NSCREEN] {
551 let base: i64 = i * VCL_S_W
552 let bit: i64 = vcl_vec_at(sc, base + VCL_S_BIT)
553 let kind: i64 = vcl_vec_at(sc, base + VCL_S_KIND)
554 var hit: i64 = 0
555 if kind == VCL_SK_CLASS { if role_counts[vcl_vec_at(sc, base + VCL_S_ARG)] > 0 { hit = 1 } }
556 if kind == VCL_SK_NAME { hit = vcl_match(VCL_K_CONTAINS, id_lc, idl, vcl_at(str, vcl_vec_at(sc, base + VCL_S_ARG)), vcl_vec_at(sc, base + VCL_S_LEN)) }
557 if hit == 1 {
558 var b: i64 = 1
559 var s: i64 = 0
560 while s < bit { b = b * 2; s = s + 1 }
561 if (mask / b) % 2 == 0 { mask = mask + b }
562 }
563 i = i + 1
564 }
565 return mask
566}
567
568// the deptag of one lowercased dependency id (first matching deptag row), or -1
569func vcl_deptag(rs: *i64, dep_lc: *u8, dl: i64) -> i64 {
570 let tg: *i64 = rs[VCL_RS_DEPTAG] as *i64
571 let str: *i64 = rs[VCL_RS_STR] as *i64
572 var i: i64 = 0
573 while i < rs[VCL_RS_NDEPTAG] {
574 let base: i64 = i * VCL_T_W
575 if vcl_match(VCL_K_PREFIX, dep_lc, dl, vcl_at(str, vcl_vec_at(tg, base + VCL_T_P)), vcl_vec_at(tg, base + VCL_T_L)) == 1 {
576 return vcl_vec_at(tg, base + VCL_T_TAG)
577 }
578 i = i + 1
579 }
580 return 0 - 1
581}
582
583// write the letters of a reason mask (A..Z) into a; "-" when empty
584func vcl_app_reasons(a: *i64, mask: i64) -> i64 {
585 if mask == 0 { return vcl_appc(a, 45) }
586 var m: i64 = mask
587 var bit: i64 = 0
588 while bit < VCL_REASONS {
589 if m % 2 == 1 { vcl_appc(a, VCL_UPPER_A + bit) }
590 m = m / 2
591 bit = bit + 1
592 }
593 return 1
594}