code wiki / (root) / nx_mccabe_gate.nx

nx_mccabe_gate.nx source

↩ module page · 286 lines · 15341 B

1// nx_mccabe_gate.nx -- teeth for the cyclomatic-complexity census. 2// 3// IN-PROCESS: imports nx_mccabe_lib.nx and calls mc_scan_file directly, so it exercises the SAME code the 4// census runs and has no NOT-DEPLOYED failure mode. 5// 6// EVERY v(G) BELOW WAS COMPUTED BY HAND FIRST AND IS WRITTEN INTO THE TOOTH NAME. A complexity organ that is 7// only checked against itself is unfalsifiable; these are six shapes whose answers are known independently. 8// 9// THE TWO TEETH THAT MATTER MOST ARE THE TRAPS. The trivial wrong implementation is a text search for the 10// keywords, and it passes every counting tooth here -- only the COMMENT trap and the STRING trap refute it. 11// Measured on the real corpus before this organ existed: the first `&&` occurrences a naive search finds are 12// all inside comments. A SCANNER THAT DOES NOT SKIP COMMENTS MEASURES THE DOCUMENTATION, NOT THE CODE. 13// 14// Fixtures are planted at runtime under /tmp/mccabe_gate/ and unlinked before creation, so the gate is 15// idempotent and shares nothing with any production beat. 16// license_tier: ORIGINAL expect_exit: 0 17import "nx_mccabe_lib.nx" 18import "nx_gate_verdict.nx" 19 20const MCG_DIR: *u8 = "/tmp/mccabe_gate\x00" 21const MCG_MODE644: i64 = 420 22const MCG_MODE755: i64 = 493 23const MCG_NFIX: i64 = 9 // fixture files planted; binds the denominator so no tooth passes on the empty set 24// CE1 class-join fixtures live in a SEPARATE dir so the nine-fixture walk above stays exact, with a PLANTED table -- 25// a gate that read the production conf would track that conf, not the code. 26const MCG_CLSDIR: *u8 = "/tmp/mccabe_gate_cls\x00" 27const MCG_CLSROWS: i64 = 2 // rows in the planted table 28const MCG_CLSFIX: i64 = 5 // class fixtures planted 29const MCG_ROW_BUILDER: i64 = 1 // planted table order: BUILDER first, so a head carrying both markers reads BUILDER 30const MCG_ROW_GENERATED: i64 = 2 31const MCG_CLS_BUILDER_FILES: i64 = 2 // g_builder + g_both (first row wins) 32const MCG_CLS_GEN_FILES: i64 = 1 // g_gen only -- g_late carries the marker BEYOND the head window 33const MCG_CLS_UNMARKED_FILES: i64 = 2 // g_plain + g_late 34const MCG_CLS_GEN_VG: i64 = 2 // g_gen: one if, hand-computed 35 36func mcg_put(path: *u8, data: *u8) -> i64 { 37 sys_unlinkat(path) 38 let fd: i64=sys_openat_wr(path, MCG_MODE644) 39 if fd<0 { return 0-1 } 40 var n: i64=0 41 while data[n]!=(0 as u8) { n=n+1 } 42 if n>0 { sys_write(fd, data, n) } 43 sys_close(fd) 44 return n 45} 46func mcg_path(buf: *u8, name: *u8) -> i64 { 47 var a: i64=mc_cat(buf, 0, MCG_DIR as *u8) 48 a=mc_cat(buf, a, "/" as *u8) 49 a=mc_cat(buf, a, name) 50 buf[a]=0 as u8 51 return a 52} 53func mcg_clspath(buf: *u8, name: *u8) -> i64 { 54 var a: i64=mc_cat(buf, 0, MCG_CLSDIR as *u8) 55 a=mc_cat(buf, a, "/" as *u8) 56 a=mc_cat(buf, a, name) 57 buf[a]=0 as u8 58 return a 59} 60// scan ONE single-function fixture and return that function's v(G); nf[0] receives the function count 61func mcg_vg(path: *u8, nf: *i64) -> i64 { 62 let hist: *i64=sys_mmap(MC_HIST_MAX*8+64) as *i64 63 var z: i64=0 64 while z<MC_HIST_MAX { hist[z]=0; z=z+1 } 65 let c: *i64=sys_mmap(128) as *i64 66 var y: i64=0 67 while y<8 { c[y]=0; y=y+1 } 68 let work: *u8=sys_mmap(65536) 69 let wo: *i64=sys_mmap(16) as *i64 70 wo[0]=0 71 mc_scan_file(path, hist, c, work, wo) 72 nf[0]=c[MC_C_FUNCS] 73 return c[MC_C_MAX] 74} 75 76func main(argc: i64, argv: *i64) -> i64 { 77 gv_head("=== NX-MCCABE-GATE -- does v(G) match a hand-computed answer, and does it ignore prose? ===" as *u8) 78 let ctr: *i64=gv_ctr() 79 sys_mkdir(MCG_DIR as *u8, MCG_MODE755) 80 let pb: *u8=sys_mmap(1024) 81 let nf: *i64=sys_mmap(16) as *i64 82 83 // ---------- plant nine shapes with independently known answers ---------- 84 mcg_path(pb, "f1_flat.nx\x00" as *u8) 85 mcg_put(pb, "func t() -> i64 {\n return 0\n}\n" as *u8) 86 mcg_path(pb, "f2_oneif.nx\x00" as *u8) 87 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>0 { return 1 }\n return 0\n}\n" as *u8) 88 mcg_path(pb, "f3_ifelse.nx\x00" as *u8) 89 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>0 { return 1 } else { return 2 }\n}\n" as *u8) 90 mcg_path(pb, "f4_while.nx\x00" as *u8) 91 mcg_put(pb, "func t(a: i64) -> i64 {\n var i: i64=0\n while i<a { i=i+1 }\n return i\n}\n" as *u8) 92 mcg_path(pb, "f5_nested.nx\x00" as *u8) 93 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>0 { if a>5 { return 2 } }\n return 0\n}\n" as *u8) 94 mcg_path(pb, "f6_commenttrap.nx\x00" as *u8) 95 mcg_put(pb, "func t() -> i64 {\n // if while for and if again\n return 0\n}\n" as *u8) 96 mcg_path(pb, "f7_stringtrap.nx\x00" as *u8) 97 mcg_put(pb, "func t() -> i64 {\n let s: *u8 = \x22if while for if\x22 as *u8\n return 0\n}\n" as *u8) 98 mcg_path(pb, "f8_andand.nx\x00" as *u8) 99 mcg_put(pb, "func t(a: i64, b: i64) -> i64 {\n if a>0 { if b>0 { return 1 } }\n return 0\n}\n" as *u8) 100 mcg_path(pb, "f9_deep.nx\x00" as *u8) 101 mcg_put(pb, "func t(a: i64) -> i64 {\n if a>1 { }\n if a>2 { }\n if a>3 { }\n if a>4 { }\n if a>5 { }\n if a>6 { }\n if a>7 { }\n if a>8 { }\n if a>9 { }\n if a>10 { }\n if a>11 { }\n if a>12 { }\n return 0\n}\n" as *u8) 102 103 // ---------- ANTI-VACUITY FIRST: a count-everything implementation dies here ---------- 104 mcg_path(pb, "f1_flat.nx\x00" as *u8); let v1: i64=mcg_vg(pb, nf) 105 var ok1: i64=0 106 if v1==1 { if nf[0]==1 { ok1=1 } } 107 gv_check("neg-control-anti-vacuity-a-straight-line-function-is-exactly-vG-1" as *u8, ok1, ctr) 108 109 mcg_path(pb, "f2_oneif.nx\x00" as *u8); let v2: i64=mcg_vg(pb, nf) 110 var ok2: i64=0 111 if v2==2 { ok2=1 } 112 gv_check("one-if-is-vG-2-hand-computed" as *u8, ok2, ctr) 113 114 mcg_path(pb, "f3_ifelse.nx\x00" as *u8); let v3: i64=mcg_vg(pb, nf) 115 var ok3: i64=0 116 if v3==2 { ok3=1 } 117 gv_check("neg-control-else-is-NOT-a-decision-point-if-else-stays-vG-2" as *u8, ok3, ctr) 118 119 mcg_path(pb, "f4_while.nx\x00" as *u8); let v4: i64=mcg_vg(pb, nf) 120 var ok4: i64=0 121 if v4==2 { ok4=1 } 122 gv_check("one-while-is-vG-2-hand-computed" as *u8, ok4, ctr) 123 124 mcg_path(pb, "f5_nested.nx\x00" as *u8); let v5: i64=mcg_vg(pb, nf) 125 var ok5: i64=0 126 if v5==3 { ok5=1 } 127 gv_check("two-nested-ifs-are-vG-3-hand-computed" as *u8, ok5, ctr) 128 129 // ---------- THE TRAPS: the keyword-grep implementation passes everything above and dies here ---------- 130 // A TRUE BITE PAIR: BOTH SIGNALS PRESENT AT ONCE. Two tests that each isolate one signal do not prove 131 // discrimination -- the detector under test is "does vG exceed 1", the BAD input is a function with REAL 132 // nested decisions (it must fire) and the GOOD input is a function whose only keywords are PROSE (it must 133 // stay silent). A keyword-grep implementation fires on both and dies here. 134 mcg_path(pb, "f6_commenttrap.nx\x00" as *u8); let v6: i64=mcg_vg(pb, nf) 135 var fires_real: i64=0 136 if v5>1 { fires_real=1 } 137 var fires_prose: i64=0 138 if v6>1 { fires_prose=1 } 139 gv_bite("discriminates-REAL-decisions-from-the-same-keywords-in-a-COMMENT" as *u8, fires_real, fires_prose, ctr) 140 var exact6: i64=0 141 if v6==1 { exact6=1 } 142 gv_check("comment-trap-lands-on-exactly-vG-1-not-merely-lower" as *u8, exact6, ctr) 143 144 mcg_path(pb, "f7_stringtrap.nx\x00" as *u8); let v7: i64=mcg_vg(pb, nf) 145 var fires_lit: i64=0 146 if v7>1 { fires_lit=1 } 147 gv_bite("discriminates-REAL-decisions-from-the-same-keywords-in-a-STRING-LITERAL" as *u8, fires_real, fires_lit, ctr) 148 var exact7: i64=0 149 if v7==1 { exact7=1 } 150 gv_check("string-trap-lands-on-exactly-vG-1-not-merely-lower" as *u8, exact7, ctr) 151 152 mcg_path(pb, "f8_andand.nx\x00" as *u8); let v8: i64=mcg_vg(pb, nf) 153 var ok8: i64=0 154 if v8==3 { ok8=1 } 155 gv_check("two-guards-are-vG-3-hand-computed" as *u8, ok8, ctr) 156 157 // ---------- the cited bar fires, and only where it should ---------- 158 mcg_path(pb, "f9_deep.nx\x00" as *u8); let v9: i64=mcg_vg(pb, nf) 159 var badhi: i64=0 160 if v9>MC_LIMIT { badhi=1 } 161 var goodhi: i64=0 162 if v1>MC_LIMIT { goodhi=1 } 163 gv_bite("above-the-cited-limit-of-10-fires-on-a-13-and-is-silent-on-a-1" as *u8, badhi, goodhi, ctr) 164 var ok9: i64=0 165 if v9==13 { ok9=1 } 166 gv_check("twelve-ifs-are-vG-13-hand-computed" as *u8, ok9, ctr) 167 168 // ---------- a whole-directory walk: denominator bound, and the worklist names the offender ---------- 169 let hist: *i64=sys_mmap(MC_HIST_MAX*8+64) as *i64 170 var z: i64=0 171 while z<MC_HIST_MAX { hist[z]=0; z=z+1 } 172 let c: *i64=sys_mmap(128) as *i64 173 var y: i64=0 174 while y<8 { c[y]=0; y=y+1 } 175 let work: *u8=sys_mmap(MC_WORKCAP) 176 let wo: *i64=sys_mmap(16) as *i64 177 wo[0]=0 178 let wp: *u8=sys_mmap(MC_PATHCAP) 179 let dn: i64=mc_cat(wp, 0, MCG_DIR as *u8) 180 mc_walk(wp, dn, 0, hist, c, work, wo) 181 var okf: i64=0 182 if c[MC_C_FILES]==MCG_NFIX { if c[MC_C_FUNCS]==MCG_NFIX { okf=1 } } 183 gv_check("the-walk-reached-all-nine-fixtures-and-found-all-nine-functions" as *u8, okf, ctr) 184 var okab: i64=0 185 if c[MC_C_ABOVE]==1 { okab=1 } 186 gv_check("exactly-one-fixture-is-above-the-cited-bar-not-zero-and-not-all" as *u8, okab, ctr) 187 var okwl: i64=0 188 if wo[0]>0 { okwl=1 } 189 gv_check("the-count-carries-its-worklist-the-offender-is-NAMED" as *u8, okwl, ctr) 190 var okp: i64=0 191 let p50: i64=mc_pct(hist, c[MC_C_FUNCS], c[MC_C_OVER], c[MC_C_MAX], 500) 192 if p50>=1 { if p50<=c[MC_C_MAX] { okp=1 } } 193 gv_check("p50-derived-from-the-CDF-lies-inside-the-observed-range" as *u8, okp, ctr) 194 195 // ---------- CE1: the head-marker class join, on planted fixtures in a SEPARATE dir with a PLANTED table ---------- 196 sys_mkdir(MCG_CLSDIR as *u8, MCG_MODE755) 197 let cp: *u8=sys_mmap(1024) 198 mcg_clspath(cp, "classes.conf\x00" as *u8) 199 mcg_put(cp, "BUILDER|AUTHORED BY THE NISHI BUILDER\nGENERATED|GENERATED\n" as *u8) 200 mcg_clspath(cp, "g_gen.nx\x00" as *u8) 201 mcg_put(cp, "// GENERATED by a fixture planter\nfunc t(a: i64) -> i64 {\n if a>0 { return 1 }\n return 0\n}\n" as *u8) 202 mcg_clspath(cp, "g_builder.nx\x00" as *u8) 203 mcg_put(cp, "// AUTHORED BY THE NISHI BUILDER (pattern: FIXTURE)\nfunc t() -> i64 {\n return 0\n}\n" as *u8) 204 mcg_clspath(cp, "g_plain.nx\x00" as *u8) 205 mcg_put(cp, "func t() -> i64 {\n return 0\n}\n" as *u8) 206 mcg_clspath(cp, "g_both.nx\x00" as *u8) 207 mcg_put(cp, "// GENERATED but also AUTHORED BY THE NISHI BUILDER -- the FIRST table row wins\nfunc t() -> i64 {\n return 0\n}\n" as *u8) 208 mcg_clspath(cp, "g_late.nx\x00" as *u8) 209 mcg_put(cp, "// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// filler filler filler filler filler filler filler filler filler filler filler filler filler filler filler\n// GENERATED beyond the head window\nfunc t() -> i64 {\n return 0\n}\n" as *u8) 210 let cc: *i64=sys_mmap(MC_C_SLOTS*8) as *i64 211 var cy: i64=0 212 while cy<MC_C_SLOTS { cc[cy]=0; cy=cy+1 } 213 mcg_clspath(cp, "classes.conf\x00" as *u8) 214 let crows: i64=mc_cls_load_from(cc, cp) 215 var okcr: i64=0 216 if crows==MCG_CLSROWS { okcr=1 } 217 gv_check("class-table-loads-exactly-two-rows-from-the-planted-conf" as *u8, okcr, ctr) 218 let chist: *i64=sys_mmap(MC_HIST_MAX*8+64) as *i64 219 var cz: i64=0 220 while cz<MC_HIST_MAX { chist[cz]=0; cz=cz+1 } 221 let cwork: *u8=sys_mmap(65536) 222 let cwo: *i64=sys_mmap(16) as *i64 223 cwo[0]=0 224 let cwp: *u8=sys_mmap(MC_PATHCAP) 225 let cdn: i64=mc_cat(cwp, 0, MCG_CLSDIR as *u8) 226 mc_walk(cwp, cdn, 0, chist, cc, cwork, cwo) 227 let bU: i64=MC_C_CLSBASE 228 let bB: i64=MC_C_CLSBASE+MCG_ROW_BUILDER*MC_CLS_FIELDS 229 let bG: i64=MC_C_CLSBASE+MCG_ROW_GENERATED*MC_CLS_FIELDS 230 var okwalk: i64=0 231 if cc[MC_C_FILES]==MCG_CLSFIX { okwalk=1 } 232 gv_check("the-class-walk-reached-all-five-class-fixtures" as *u8, okwalk, ctr) 233 var okg: i64=0 234 if cc[bG+MC_CF_FILES]==MCG_CLS_GEN_FILES { if cc[bG+MC_CF_FUNCS]==MCG_CLS_GEN_FILES { if cc[bG+MC_CF_SUMVG]==MCG_CLS_GEN_VG { okg=1 } } } 235 gv_check("generated-head-marker-classifies-into-the-GENERATED-row-carrying-its-hand-computed-vG-2" as *u8, okg, ctr) 236 var okb: i64=0 237 if cc[bB+MC_CF_FILES]==MCG_CLS_BUILDER_FILES { okb=1 } 238 gv_check("neg-control-first-matching-row-wins-a-head-carrying-BOTH-markers-reads-the-FIRST-row-BUILDER" as *u8, okb, ctr) 239 var oku: i64=0 240 if cc[bU+MC_CF_FILES]==MCG_CLS_UNMARKED_FILES { oku=1 } 241 gv_check("neg-control-a-marker-beyond-the-head-window-does-NOT-classify-a-whole-file-grep-dies-here" as *u8, oku, ctr) 242 var cps: i64=0 243 var cpn2: i64=0 244 var ci: i64=0 245 while ci<=crows { let cbi: i64=MC_C_CLSBASE+ci*MC_CLS_FIELDS; cps=cps+cc[cbi+MC_CF_FILES]; cpn2=cpn2+cc[cbi+MC_CF_FUNCS]; ci=ci+1 } 246 var oksum: i64=0 247 if cps==cc[MC_C_FILES] { if cpn2==cc[MC_C_FUNCS] { if cps==MCG_CLSFIX { oksum=1 } } } 248 gv_check("class-partition-sums-files-and-funcs-to-the-walk-and-the-walk-is-not-empty" as *u8, oksum, ctr) 249 // absent table: classification OFF, no class block written, the scan itself unchanged 250 let c2: *i64=sys_mmap(MC_C_SLOTS*8) as *i64 251 var c2y: i64=0 252 while c2y<MC_C_SLOTS { c2[c2y]=0; c2y=c2y+1 } 253 mcg_clspath(cp, "nope.conf\x00" as *u8) 254 let r2: i64=mc_cls_load_from(c2, cp) 255 mcg_clspath(cp, "g_gen.nx\x00" as *u8) 256 mc_scan_file(cp, chist, c2, cwork, cwo) 257 var okab2: i64=0 258 if r2==0 { if c2[MC_C_FILES]==1 { if c2[MC_C_CLSBASE+MC_CF_FILES]==0 { if c2[bG+MC_CF_FILES]==0 { okab2=1 } } } } 259 gv_check("neg-control-an-absent-table-classifies-nothing-and-writes-no-class-block" as *u8, okab2, ctr) 260 gv_puts(" class join: rows=" as *u8); gv_num(crows); gv_puts(" files=" as *u8); gv_num(cc[MC_C_FILES]); gv_puts(" UNMARKED=" as *u8); gv_num(cc[bU+MC_CF_FILES]); gv_puts(" BUILDER=" as *u8); gv_num(cc[bB+MC_CF_FILES]); gv_puts(" GENERATED=" as *u8); gv_num(cc[bG+MC_CF_FILES]); gv_puts(" gen_sumvG=" as *u8); gv_num(cc[bG+MC_CF_SUMVG]); gv_puts("\n" as *u8) 261 262 // ---------- idempotence ---------- 263 mcg_path(pb, "f9_deep.nx\x00" as *u8) 264 let again: i64=mcg_vg(pb, nf) 265 var okid: i64=0 266 if again==v9 { okid=1 } 267 gv_check("idempotent-a-second-scan-returns-the-same-vG" as *u8, okid, ctr) 268 269 gv_puts("\n observed vG: flat=" as *u8); gv_num(v1) 270 gv_puts(" oneif=" as *u8); gv_num(v2) 271 gv_puts(" ifelse=" as *u8); gv_num(v3) 272 gv_puts(" while=" as *u8); gv_num(v4) 273 gv_puts(" nested=" as *u8); gv_num(v5) 274 gv_puts(" commenttrap=" as *u8); gv_num(v6) 275 gv_puts(" stringtrap=" as *u8); gv_num(v7) 276 gv_puts(" twoguards=" as *u8); gv_num(v8) 277 gv_puts(" deep=" as *u8); gv_num(v9) 278 gv_puts("\n walk: files=" as *u8); gv_num(c[MC_C_FILES]) 279 gv_puts(" funcs=" as *u8); gv_num(c[MC_C_FUNCS]) 280 gv_puts(" above10=" as *u8); gv_num(c[MC_C_ABOVE]) 281 gv_puts(" max=" as *u8); gv_num(c[MC_C_MAX]) 282 gv_puts(" p50=" as *u8); gv_num(p50) 283 gv_puts("\n" as *u8) 284 285 return gv_verdict("mccabe" as *u8, ctr, "every expected vG in the tooth names was hand-computed before the organ was run; fixtures are runtime-planted under /tmp and unlinked before creation" as *u8) 286}