code wiki / _hdl_build / nx_varcensus_gate.nx
nx_varcensus_gate.nx source
↩ module page · 163 lines · 10747 B
1// nx_varcensus_gate.nx -- PROVE THE VaM CENSUS CLASSIFIER IS DATA, FIRST-MATCH, A PARTITION ON BOTH AXES, AND THAT A
2// MALFORMED RULE REFUSES. In-process over nx_varcensus_lib with fixture rules and fixture member names: no corpus is read and
3// no asset byte exists anywhere in this gate. The rules text is assembled at runtime with real TAB bytes.
4// license_tier: ORIGINAL No hw writes (Rule 26).
5import "nx_syscalls.nx"
6import "nx_gate_verdict.nx"
7import "nx_varcensus_lib.nx"
8
9const VG_TAB: i64 = 9
10const VG_LF: i64 = 10
11const VG_KEYS: i64 = 1000
12
13func vg_row(a: *i64, f0: *u8, f1: *u8, f2: *u8, f3: *u8, f4: *u8, f5: *u8) -> i64 {
14 vcl_apps(a, f0)
15 vcl_appc(a, VG_TAB)
16 vcl_apps(a, f1)
17 vcl_appc(a, VG_TAB)
18 vcl_apps(a, f2)
19 vcl_appc(a, VG_TAB)
20 vcl_apps(a, f3)
21 if vcl_slen(f4) > 0 {
22 vcl_appc(a, VG_TAB)
23 vcl_apps(a, f4)
24 vcl_appc(a, VG_TAB)
25 vcl_apps(a, f5)
26 }
27 vcl_appc(a, VG_LF)
28 return 0
29}
30func vg_ptr(s: *u8) -> i64 { return s as i64 }
31func vg_cls(rs: *i64, axis: i64, name: *u8) -> i64 {
32 let buf: *u8 = sys_mmap(vcl_slen(name) + 1)
33 let n: i64 = vcl_lower(name, vcl_slen(name), buf)
34 return vcl_classify(rs, axis, buf, n)
35}
36func vg_idx(rs: *i64, axis: i64, cls: *u8) -> i64 {
37 if axis == VCL_AX_ROLE { return vcl_counter_find(rs[VCL_RS_CLASS_ROLE] as *i64, cls, 0, vcl_slen(cls)) }
38 return vcl_counter_find(rs[VCL_RS_CLASS_FORMAT] as *i64, cls, 0, vcl_slen(cls))
39}
40
41func main(argc: i64, argv: *i64) -> i64 {
42 let ctr: *i64 = gv_ctr()
43 gv_head("nx_varcensus_gate -- the classifier is data, first match wins, both axes partition, a malformed rule refuses" as *u8)
44
45 let rt: *i64 = vcl_arena_new(4096)
46 vcl_apps(rt, "# fixture rules for the census gate\n" as *u8)
47 vg_row(rt, "role" as *u8, "dir" as *u8, "dirent" as *u8, "/" as *u8, "" as *u8, "" as *u8)
48 vg_row(rt, "role" as *u8, "meta" as *u8, "exact" as *u8, "meta.json" as *u8, "" as *u8, "" as *u8)
49 vg_row(rt, "role" as *u8, "scene" as *u8, "prefix" as *u8, "saves/scene/" as *u8, "" as *u8, "" as *u8)
50 vg_row(rt, "role" as *u8, "person_appearance" as *u8, "prefix" as *u8, "custom/atom/person/appearance/" as *u8, "" as *u8, "" as *u8)
51 vg_row(rt, "role" as *u8, "person_morphs" as *u8, "prefix" as *u8, "custom/atom/person/morphs/" as *u8, "" as *u8, "" as *u8)
52 vg_row(rt, "role" as *u8, "hair" as *u8, "prefix" as *u8, "custom/hair/" as *u8, "" as *u8, "" as *u8)
53 vg_row(rt, "format" as *u8, "dir" as *u8, "dirent" as *u8, "/" as *u8, "" as *u8, "" as *u8)
54 vg_row(rt, "format" as *u8, "scene_json" as *u8, "prefix" as *u8, "saves/scene/" as *u8, "suffix" as *u8, ".json" as *u8)
55 vg_row(rt, "format" as *u8, "json" as *u8, "suffix" as *u8, ".json" as *u8, "" as *u8, "" as *u8)
56 vg_row(rt, "format" as *u8, "morph_vmi" as *u8, "suffix" as *u8, ".vmi" as *u8, "" as *u8, "" as *u8)
57 vg_row(rt, "format" as *u8, "image" as *u8, "suffix" as *u8, ".jpg" as *u8, "" as *u8, "" as *u8)
58 vg_row(rt, "screen" as *u8, "A" as *u8, "class" as *u8, "person_appearance" as *u8, "" as *u8, "" as *u8)
59 vg_row(rt, "screen" as *u8, "N" as *u8, "namecontains" as *u8, "look" as *u8, "" as *u8, "" as *u8)
60 vg_row(rt, "deptag" as *u8, "timeline" as *u8, "prefix" as *u8, "acidbubbles.timeline." as *u8, "" as *u8, "" as *u8)
61 let rs: *i64 = vcl_rules_parse(vcl_at(rt, 0), vcl_used(rt))
62
63 gv_check_eq("T1 fixture rules parse with zero errors (a comment row is skipped, not counted)" as *u8, rs[VCL_RS_ERRORS], 0, ctr)
64 gv_check_eq("T1a role classes = 6 declared + the implicit other" as *u8, vcl_nclasses(rs, VCL_AX_ROLE), 7, ctr)
65 gv_check_eq("T1b format classes = 5 declared + the implicit other" as *u8, vcl_nclasses(rs, VCL_AX_FORMAT), 6, ctr)
66 gv_check_eq("T1c two screen rows and one deptag row are loaded" as *u8, rs[VCL_RS_NSCREEN] * 10 + rs[VCL_RS_NDEPTAG], 21, ctr)
67
68 // T2 FIRST MATCH WINS, and a two-condition row needs both
69 gv_check_eq("T2 a scene json takes the EARLIER two-condition row scene_json, not the later json row" as *u8, vg_cls(rs, VCL_AX_FORMAT, "Saves/scene/Creator/Pack/A.JSON" as *u8), vg_idx(rs, VCL_AX_FORMAT, "scene_json" as *u8), ctr)
70 gv_check_eq("T2a a json outside saves/scene fails the prefix condition and falls to json" as *u8, vg_cls(rs, VCL_AX_FORMAT, "Custom/Atom/Person/Pose/p.json" as *u8), vg_idx(rs, VCL_AX_FORMAT, "json" as *u8), ctr)
71 gv_check_eq("T2b matching is case-insensitive through the caller's lowercasing" as *u8, vg_cls(rs, VCL_AX_ROLE, "CUSTOM/Hair/Female/X/y.vab" as *u8), vg_idx(rs, VCL_AX_ROLE, "hair" as *u8), ctr)
72 gv_check_eq("T2c exact is exact: a nested meta.json is NOT the package meta" as *u8, vg_cls(rs, VCL_AX_ROLE, "Custom/meta.json" as *u8), rs[VCL_RS_OTHER_ROLE], ctr)
73 gv_check_eq("T2d a name no row covers lands in other" as *u8, vg_cls(rs, VCL_AX_ROLE, "luts/plut4.png" as *u8), rs[VCL_RS_OTHER_ROLE], ctr)
74
75 // T3 BOTH AXES PARTITION a fixture member list
76 let names: *i64 = vcl_arena_new(4096)
77 vcl_push(names, vg_ptr("meta.json" as *u8))
78 vcl_push(names, vg_ptr("Custom/" as *u8))
79 vcl_push(names, vg_ptr("Saves/scene/C/P/s.json" as *u8))
80 vcl_push(names, vg_ptr("Saves/scene/C/P/s.jpg" as *u8))
81 vcl_push(names, vg_ptr("Custom/Atom/Person/Morphs/female/C/a.vmi" as *u8))
82 vcl_push(names, vg_ptr("Custom/Atom/Person/Morphs/female/C/a.vmb" as *u8))
83 vcl_push(names, vg_ptr("Custom/Atom/Person/Appearance/C/look.vap" as *u8))
84 vcl_push(names, vg_ptr("readme.txt" as *u8))
85 let nn: i64 = vcl_vec_n(names)
86 let rc_role: *i64 = sys_mmap(16 * 8) as *i64
87 let rc_fmt: *i64 = sys_mmap(16 * 8) as *i64
88 var i: i64 = 0
89 while i < nn {
90 let nm: *u8 = vcl_vec_at(names, i) as *u8
91 let r: i64 = vg_cls(rs, VCL_AX_ROLE, nm)
92 let f: i64 = vg_cls(rs, VCL_AX_FORMAT, nm)
93 rc_role[r] = rc_role[r] + 1
94 rc_fmt[f] = rc_fmt[f] + 1
95 i = i + 1
96 }
97 var sr: i64 = 0
98 var sf: i64 = 0
99 i = 0
100 while i < vcl_nclasses(rs, VCL_AX_ROLE) { sr = sr + rc_role[i]; i = i + 1 }
101 i = 0
102 while i < vcl_nclasses(rs, VCL_AX_FORMAT) { sf = sf + rc_fmt[i]; i = i + 1 }
103 gv_check_eq("T3 the role axis sums to the member count" as *u8, sr, nn, ctr)
104 gv_check_eq("T3a the format axis sums to the member count" as *u8, sf, nn, ctr)
105 gv_check_eq("T3b role person_morphs holds the vmi AND the vmb" as *u8, rc_role[vg_idx(rs, VCL_AX_ROLE, "person_morphs" as *u8)], 2, ctr)
106 gv_check_eq("T3c format other holds the vmb, the vap and the txt (no rule names them in this fixture)" as *u8, rc_fmt[rs[VCL_RS_OTHER_FORMAT]], 3, ctr)
107
108 // T4 THE REAL-PERSON SCREEN: reasons from a role class count and from the package id, never adjudicated here
109 let idb: *u8 = sys_mmap(64)
110 let idn: i64 = vcl_lower("TGC.Look_Lana" as *u8, 13, idb)
111 gv_check_eq("T4 an appearance member sets reason A (bit 0) and a look token sets N (bit 13): mask 8193" as *u8, vcl_screen(rs, rc_role, idb, idn), 8193, ctr)
112 let zc: *i64 = sys_mmap(16 * 8) as *i64
113 let idb2: *u8 = sys_mmap(64)
114 let idn2: i64 = vcl_lower("AcidBubbles.Timeline" as *u8, 20, idb2)
115 gv_check_eq("neg-control-T4a a plugin package with no appearance member and no token is not flagged" as *u8, vcl_screen(rs, zc, idb2, idn2), 0, ctr)
116
117 // T5 DEPTAG: the prefix carries its trailing dot, so a lookalike id is not tagged
118 gv_check_eq("T5 acidbubbles.timeline.210 is tagged timeline (tag 0)" as *u8, vcl_deptag(rs, "acidbubbles.timeline.210" as *u8, 24), 0, ctr)
119 gv_check_eq("neg-control-T5a acidbubbles.timelinex.1 is NOT tagged" as *u8, vcl_deptag(rs, "acidbubbles.timelinex.1" as *u8, 23), 0 - 1, ctr)
120
121 // T6 THE COUNTER GROWS PAST ITS INITIAL SLOT TABLE WITHOUT LOSING A KEY
122 let c: *i64 = vcl_counter_new()
123 let kb: *i64 = vcl_arena_new(64)
124 i = 0
125 while i < VG_KEYS {
126 kb[VCL_A_USED] = 0
127 vcl_appc(kb, 107)
128 vcl_appn(kb, i)
129 vcl_counter_add(c, vcl_at(kb, 0), 0, vcl_used(kb), 1)
130 i = i + 1
131 }
132 vcl_counter_add(c, "k7" as *u8, 0, 2, 1)
133 gv_check_eq("T6 1000 distinct keys survive three rehashes" as *u8, vcl_counter_n(c), VG_KEYS, ctr)
134 gv_check_eq("T6a a repeated key increments, it does not duplicate" as *u8, vcl_counter_count(c, vcl_counter_find(c, "k7" as *u8, 0, 2)), 2, ctr)
135 gv_check("T6b the last key is findable after growth" as *u8, (vcl_counter_find(c, "k999" as *u8, 0, 4) >= 0) as i64, ctr)
136 gv_check_eq("neg-control-T6c a key never added is not found" as *u8, vcl_counter_find(c, "k1000" as *u8, 0, 5), 0 - 1, ctr)
137
138 // T7 A MALFORMED RULE REFUSES, WITH ITS LINE NUMBER
139 let bad: *i64 = vcl_arena_new(1024)
140 vg_row(bad, "role" as *u8, "scene" as *u8, "prefix" as *u8, "saves/scene/" as *u8, "" as *u8, "" as *u8)
141 vg_row(bad, "role" as *u8, "hair" as *u8, "startswith" as *u8, "custom/hair/" as *u8, "" as *u8, "" as *u8)
142 let rb: *i64 = vcl_rules_parse(vcl_at(bad, 0), vcl_used(bad))
143 gv_check_eq("neg-control-T7 an unknown match kind is ONE error" as *u8, rb[VCL_RS_ERRORS], 1, ctr)
144 gv_check_eq("neg-control-T7a and the error names line 2" as *u8, rb[VCL_RS_FIRST_ERR_LINE], 2, ctr)
145 let bad2: *i64 = vcl_arena_new(1024)
146 vg_row(bad2, "screen" as *u8, "A" as *u8, "class" as *u8, "person_appearance" as *u8, "" as *u8, "" as *u8)
147 vg_row(bad2, "role" as *u8, "hair" as *u8, "prefix" as *u8, "custom/hair/" as *u8, "" as *u8, "" as *u8)
148 let rb2: *i64 = vcl_rules_parse(vcl_at(bad2, 0), vcl_used(bad2))
149 gv_check_eq("neg-control-T7b a screen row naming an undeclared class is an error even though it precedes every class row" as *u8, rb2[VCL_RS_ERRORS], 1, ctr)
150
151 // T8 ANTI-VACUITY: an axis with no rows classifies everything as other -- a classifier that always answered its first
152 // class would pass T2 on a lucky fixture and fail here
153 let onlyrole: *i64 = vcl_arena_new(1024)
154 vg_row(onlyrole, "role" as *u8, "hair" as *u8, "prefix" as *u8, "custom/hair/" as *u8, "" as *u8, "" as *u8)
155 let ro: *i64 = vcl_rules_parse(vcl_at(onlyrole, 0), vcl_used(onlyrole))
156 gv_check_eq("T8 a rules file with no format rows yields exactly one format class" as *u8, vcl_nclasses(ro, VCL_AX_FORMAT), 1, ctr)
157 gv_check_eq("T8a and every name lands in it" as *u8, vg_cls(ro, VCL_AX_FORMAT, "Custom/Hair/F/C/h.vab" as *u8), ro[VCL_RS_OTHER_FORMAT], ctr)
158 gv_check_eq("T8b while the role axis still separates hair from other" as *u8, vg_cls(ro, VCL_AX_ROLE, "Custom/Hair/F/C/h.vab" as *u8) * 10 + vg_cls(ro, VCL_AX_ROLE, "Saves/scene/x.json" as *u8), ro[VCL_RS_OTHER_ROLE], ctr)
159
160 let rc: i64 = gv_verdict("VARCENSUS-GATE", ctr, "fixture rules and names only, first match, two partitions, refusal on a malformed rule" as *u8)
161 sys_exit(rc)
162 return rc
163}