code wiki / (root) / nx_glsl_tokdiff_gate.nx

nx_glsl_tokdiff_gate.nx source

↩ module page · 185 lines · 15112 B

1// nx_glsl_tokdiff_gate.nx -- referee for THE SHADER TOKEN RULER (nx_glsl_tok_lib), driven IN-PROCESS over planted 2// strings, both directions: every normalisation the ruler claims (whitespace, comments, numeric spelling, compound 3// assignment over ident / swizzle / index lvalues -- and, since S12c-2, THE CANONICAL FORM: precedence re-parenthesisation, 4// multi-declarator splitting, brace insertion, else-if nesting, counted-loop lowering, comparison inversion under not) must 5// read IDENTICAL, and every real difference (an operator, a constant, an identifier, an extra token, a parenthesis that 6// CHANGES precedence) must read DIFFERS naming the first differing token index -- plus the tokenizer's own arithmetic on a 7// string whose token count is known by hand, an unreadable input REFUSED by name, and the real subject (the hand MVS on the 8// board) canonicalising to itself with parentheses ADDED. Every number asserted AND emitted. 9// STATEMENT fixtures are wrapped in braces: module scope is copied token for token by design (a function HEADER `float 10// hsh(float s)` is `IDENT IDENT (` and must not be read as a declaration), so a statement-level normalisation is only 11// reachable inside a block -- exactly where every statement of a real shader lives. The first run of this gate measured that 12// (T9/T10/T12/T13 read DIFFERS at module scope, 35/40): the fixtures were wrong, the ruler was not. 13// license_tier: ORIGINAL No hw writes (Rule 26). 14import "nx_glsl_tok_lib.nx" 15import "nx_gate_verdict.nx" 16 17const C_TILDE: i64 = 126 18 19func g_diff(a: *u8, b: *u8, r: *i64) -> i64 { return gt_diff(a, gt_slen(a), b, gt_slen(b), r) } 20func g_cdiff(a: *u8, b: *u8, r: *i64) -> i64 { return gt_diff_canon(a, gt_slen(a), b, gt_slen(b), r) } 21// a planted fixture that needs a bang: nx_cc source carries none inside a literal, so the fixture is written with '~' (126) 22// and every tilde becomes '!' (33) at run time -- the byte the ruler will actually see. 23func g_bang(s: *u8) -> *u8 { 24 let n: i64 = gt_slen(s) 25 let o: *u8 = sys_mmap(n + 1) 26 var i: i64 = 0 27 while i < n { 28 var c: i64 = s[i] as i64 29 if c == C_TILDE { c = C_BANG } 30 o[i] = c as u8 31 i = i + 1 32 } 33 o[n] = 0 as u8 34 return o 35} 36 37func main() -> i64 { 38 let ctr: *i64 = gv_ctr() 39 let r: *i64 = sys_mmap(GT_R_SLOTS * 8) as *i64 40 // T1 whitespace + line comment + numeric spelling + compound `/=` on an ident lvalue 41 let a1: *u8 = "vec3 a=vec3(0.);\nfloat b=.5*a.x;\nb/=2.;\n" as *u8 42 let b1: *u8 = "vec3 a = vec3( 0.0 ) ; // the same program, spelled for people\n float b = 0.5 * a.x ;\n b = b / 2.0 ;" as *u8 43 let v1: i64 = g_diff(a1, b1, r) 44 // captured HERE, because r is refilled by every later diff and the value published at the end must be the one tested 45 let t1_tokens: i64 = r[GT_R_TOKA] 46 let t1_expanded: i64 = r[GT_R_EXPA] 47 gv_check_eq("T1-whitespace-comment-numeric-and-compound-normalise-to-IDENTICAL" as *u8, v1, GT_V_IDENTICAL, ctr) 48 // hand count (corrected on the first run: the ruler read 21 and it was right -- `.5*a.x` is FIVE tokens, not six): 49 // vec3 a = vec3 ( 0. ) ; | float b = .5 * a . x ; | b /= 2. ; -> 8 + 9 + 4 = 21 raw; the one compound adds 2 -> 23. 50 gv_check_eq("T1-raw-token-count-of-the-terse-spelling-is-known-by-hand (21)" as *u8, r[GT_R_TOKA], 21, ctr) 51 gv_check_eq("T1-expanded-streams-agree-in-length (23)" as *u8, r[GT_R_EXPA], r[GT_R_EXPB], ctr) 52 gv_check_eq("T1-expanded-length-is-raw-plus-two-per-compound (23)" as *u8, r[GT_R_EXPA], 23, ctr) 53 gv_check_eq("T1-no-compound-refused" as *u8, r[GT_R_REFUSED], 0, ctr) 54 // T2 swizzle lvalue `aP2.z+=` expands to `aP2.z=aP2.z+` 55 let v2: i64 = g_diff("aP2.z+=704.*w1;" as *u8, "aP2.z=aP2.z+704.0*w1;" as *u8, r) 56 gv_check_eq("T2-swizzle-lvalue-compound-expands-IDENTICAL" as *u8, v2, GT_V_IDENTICAL, ctr) 57 // T3 indexed lvalue with an expression index `uSB[ii*6+1]+=` 58 let v3: i64 = g_diff("uSB[ii*6+1]+=w;" as *u8, "uSB[ii*6+1]=uSB[ii*6+1]+w;" as *u8, r) 59 gv_check_eq("T3-indexed-lvalue-compound-expands-IDENTICAL" as *u8, v3, GT_V_IDENTICAL, ctr) 60 // T4 block comment + trailing-f literal 61 let v4: i64 = g_diff("/* c */ x=2.0f;" as *u8, "x=2.;" as *u8, r) 62 gv_check_eq("T4-block-comment-and-2.0f-vs-2.-IDENTICAL" as *u8, v4, GT_V_IDENTICAL, ctr) 63 // T5 multi-char operators are ONE token each 64 let v5: i64 = g_diff("a>=b<<c" as *u8, "a >= b << c" as *u8, r) 65 gv_check_eq("T5-multichar-ops-IDENTICAL" as *u8, v5, GT_V_IDENTICAL, ctr) 66 gv_check_eq("T5-multichar-ops-tokenize-as-five" as *u8, r[GT_R_TOKA], 5, ctr) 67 // NEG-CONTROLS: a real difference must fire, at the right token 68 let n1: i64 = g_diff("a=b+c;" as *u8, "a=b-c;" as *u8, r) 69 gv_check_eq("neg-control-operator-change-DIFFERS" as *u8, n1, GT_V_DIFFERS, ctr) 70 gv_check_eq("neg-control-operator-change-names-token-3" as *u8, r[GT_R_FIRSTDIFF], 3, ctr) 71 let n2: i64 = g_diff("float x=1e-6;" as *u8, "float x=1e-5;" as *u8, r) 72 gv_check_eq("neg-control-exponent-constant-change-DIFFERS" as *u8, n2, GT_V_DIFFERS, ctr) 73 let n3: i64 = g_diff("vec3 wp=uIP[ii];" as *u8, "vec3 wp=uIH[ii];" as *u8, r) 74 gv_check_eq("neg-control-identifier-change-DIFFERS" as *u8, n3, GT_V_DIFFERS, ctr) 75 let n4: i64 = g_diff("a=b;" as *u8, "a=b;c=d;" as *u8, r) 76 gv_check_eq("neg-control-extra-statement-DIFFERS-at-the-end-of-the-shorter" as *u8, n4, GT_V_DIFFERS, ctr) 77 gv_check_eq("neg-control-extra-statement-first-diff-is-the-shorter-length (4)" as *u8, r[GT_R_FIRSTDIFF], 4, ctr) 78 let n5: i64 = g_diff("x=.5;" as *u8, "x=.55;" as *u8, r) 79 gv_check_eq("neg-control-numeric-canon-does-not-collapse-different-values" as *u8, n5, GT_V_DIFFERS, ctr) 80 // a compound whose lvalue shape is not in the grammar is COUNTED, never guessed: `f(x)+=1` (a call is not an lvalue) 81 let v6: i64 = g_diff("f(x)+=1;" as *u8, "f(x)+=1;" as *u8, r) 82 gv_check_eq("T6-non-lvalue-compound-left-literal-still-IDENTICAL-to-itself" as *u8, v6, GT_V_IDENTICAL, ctr) 83 gv_check_eq("T6-non-lvalue-compound-is-COUNTED-as-refused (2 = both sides)" as *u8, r[GT_R_REFUSED], 2, ctr) 84 85 // ---- S12c-2: THE CANONICAL FORM -- each normalisation bitten in both directions ---- 86 // T7 a redundant parenthesis vanishes: a+b*c and (a+(b*c)) are ONE tree 87 let v7: i64 = g_cdiff("x=a+b*c;" as *u8, "x=(a+(b*c));" as *u8, r) 88 gv_check_eq("T7-redundant-parentheses-canonicalise-IDENTICAL" as *u8, v7, GT_V_IDENTICAL, ctr) 89 gv_check_eq("T7-canonical-streams-agree-in-length" as *u8, r[GT_R_CANA], r[GT_R_CANB], ctr) 90 // NEG-CONTROL a parenthesis that CHANGES precedence survives: (a+b)*c is not a+b*c 91 let n7: i64 = g_cdiff("x=(a+b)*c;" as *u8, "x=a+b*c;" as *u8, r) 92 gv_check_eq("neg-control-meaningful-parenthesis-DIFFERS" as *u8, n7, GT_V_DIFFERS, ctr) 93 // T8 the precedence table: comparison binds tighter than logical and 94 let v8: i64 = g_cdiff("x=a<b&&c>d;" as *u8, "x=((a<b)&&(c>d));" as *u8, r) 95 gv_check_eq("T8-precedence-comparison-over-logical-and-IDENTICAL" as *u8, v8, GT_V_IDENTICAL, ctr) 96 // T9 one declarator per statement (inside a block, where declarations live) 97 let v9: i64 = g_cdiff("{float a=1.,b=a*2.;}" as *u8, "{float a=1.0;float b=(a*2.0);}" as *u8, r) 98 gv_check_eq("T9-multi-declarator-splits-IDENTICAL" as *u8, v9, GT_V_IDENTICAL, ctr) 99 // NEG-CONTROL the same two declarators at MODULE scope are NOT identified: module scope is copied, never restructured 100 let n9m: i64 = g_cdiff("float a=1.,b=a*2.;" as *u8, "float a=1.0;float b=(a*2.0);" as *u8, r) 101 gv_check_eq("neg-control-module-scope-is-copied-not-restructured-DIFFERS" as *u8, n9m, GT_V_DIFFERS, ctr) 102 // T10 brace-less branches are braced and `else if` nests 103 let v10: i64 = g_cdiff("{if(a)x=1.;else if(b)x=2.;else x=3.;}" as *u8, "{if(a){x=1.0;}else{if(b){x=2.0;}else{x=3.0;}}}" as *u8, r) 104 gv_check_eq("T10-braceless-if-else-if-chain-IDENTICAL" as *u8, v10, GT_V_IDENTICAL, ctr) 105 // T11 the ternary and unary minus print in the backend's own shape 106 let v11: i64 = g_cdiff("{float s=d<0.?-1.:1.;}" as *u8, "{float s=((d<0.0)?(-1.0):1.0);}" as *u8, r) 107 gv_check_eq("T11-ternary-and-unary-minus-IDENTICAL" as *u8, v11, GT_V_IDENTICAL, ctr) 108 // T12 a counted loop lowers to the IR's init;while(true){if(until){break;}body;step;} with i++ spelled i=(i+1) 109 let v12: i64 = g_cdiff("{for(int i=0;i<n;i++){s+=f(i);}}" as *u8, "{int i=0;while(true){if((i>=n)){break;}s=(s+f(i));i=(i+1);}}" as *u8, r) 110 gv_check_eq("T12-counted-loop-lowers-to-while-true-IDENTICAL" as *u8, v12, GT_V_IDENTICAL, ctr) 111 // T13 not-of-a-comparison prints as the inverted comparison; not-of-anything-else is preserved 112 let v13: i64 = g_cdiff(g_bang("{if(~(a<b))x=1.;}" as *u8), "{if((a>=b)){x=1.0;}}" as *u8, r) 113 gv_check_eq("T13-not-of-comparison-inverts-IDENTICAL" as *u8, v13, GT_V_IDENTICAL, ctr) 114 let v13b: i64 = g_cdiff(g_bang("{if(~q)x=1.;}" as *u8), g_bang("{if((~q)){x=1.0;}}" as *u8), r) 115 gv_check_eq("T13-not-of-identifier-is-preserved-IDENTICAL" as *u8, v13b, GT_V_IDENTICAL, ctr) 116 // NEG-CONTROL not-of-a-comparison is NOT identified with the un-inverted comparison 117 let n13: i64 = g_cdiff(g_bang("{if(~(a<b))x=1.;}" as *u8), "{if((a<b)){x=1.0;}}" as *u8, r) 118 gv_check_eq("neg-control-inverted-comparison-DIFFERS-from-the-original" as *u8, n13, GT_V_DIFFERS, ctr) 119 // T14 the canonical form is a fixed point: canon(canon(x)) == canon(x), on real statements of the hand shader 120 let a14: *u8 = "{vec3 sp=aP2+2.*cross(br.xyz,cross(br.xyz,aP2)+br.w*aP2);if(uGar==1){aP2+=texelFetch(uGD,ivec2(gl_VertexID,ii),0).xyz;}}" as *u8 121 let v14: i64 = g_cdiff(a14, a14, r) 122 gv_check_eq("T14-real-statements-self-canonical-IDENTICAL" as *u8, v14, GT_V_IDENTICAL, ctr) 123 let c14: *u8 = r[GT_R_CAPTR_A] as *u8 124 let l14: i64 = r[GT_R_CALEN_A] 125 let v14b: i64 = gt_diff_canon(c14, l14, a14, gt_slen(a14), r) 126 gv_check_eq("T14-canonical-form-is-a-fixed-point" as *u8, v14b, GT_V_IDENTICAL, ctr) 127 // T15 swizzle on a group and an expression index 128 let v15: i64 = g_cdiff("x=(a+b).x*u[i*6+1];" as *u8, "x=((a+b).x*u[((i*6)+1)]);" as *u8, r) 129 gv_check_eq("T15-swizzle-on-group-and-expression-index-IDENTICAL" as *u8, v15, GT_V_IDENTICAL, ctr) 130 // NEG-CONTROLS an unreadable input is REFUSED and named; a readable one carries no refusal; a moved parenthesis DIFFERS 131 let n8: i64 = g_cdiff("x=+;" as *u8, "x=+;" as *u8, r) 132 gv_check_eq("neg-control-unparseable-input-reads-UNREADABLE" as *u8, n8, GT_V_UNREADABLE, ctr) 133 gv_check_eq("neg-control-unparseable-input-names-the-refusing-byte (2)" as *u8, r[GT_R_ERRA], 2, ctr) 134 let n9: i64 = g_cdiff("x=a;" as *u8, "x=a;" as *u8, r) 135 gv_check_eq("neg-control-readable-input-carries-no-refusal (-1)" as *u8, r[GT_R_ERRA], 0 - 1, ctr) 136 gv_check_eq("neg-control-readable-input-IDENTICAL" as *u8, n9, GT_V_IDENTICAL, ctr) 137 let n10: i64 = g_cdiff("x=a-(b-c);" as *u8, "x=a-b-c;" as *u8, r) 138 gv_check_eq("neg-control-moved-parenthesis-DIFFERS" as *u8, n10, GT_V_DIFFERS, ctr) 139 // T17 the per-slice accept signal: a shorter canonical stream that is a PREFIX of the longer names first_diff at its own 140 // length; a shorter stream that DIVERGES names the diverging token, and the prefix flag stays 0 (computed as the report does) 141 // (measured on the first run: a braced slice is NOT a pure prefix -- its closing brace lands where the hand continues, so 142 // first_diff is the shorter length MINUS ONE and the shorter's token there is `}`; that is exactly what gt_slice_prefix reads) 143 let v17: i64 = g_cdiff("{a=b;c=d;}" as *u8, "{a=b;}" as *u8, r) 144 gv_check_eq("T17-prefix-slice-reads-DIFFERS" as *u8, v17, GT_V_DIFFERS, ctr) 145 gv_check_eq("T17-prefix-slice-first-diff-is-the-shorter-canonical-length-minus-its-closing-brace" as *u8, r[GT_R_FIRSTDIFF], r[GT_R_CANB] - 1, ctr) 146 gv_check_eq("T17-prefix-slice-slice_prefix-reads-1" as *u8, gt_slice_prefix(r), 1, ctr) 147 let v17b: i64 = g_cdiff("{a=b;c=d;}" as *u8, "{a=x;}" as *u8, r) 148 gv_check("T17-diverging-slice-first-diff-is-inside-the-shorter" as *u8, (r[GT_R_FIRSTDIFF] < r[GT_R_CANB]) as i64, ctr) 149 gv_check_eq("T17-diverging-slice-reads-DIFFERS" as *u8, v17b, GT_V_DIFFERS, ctr) 150 gv_check_eq("neg-control-diverging-slice-slice_prefix-reads-0" as *u8, gt_slice_prefix(r), 0, ctr) 151 let v17c: i64 = g_cdiff("a=b;c=d;" as *u8, "a=b;" as *u8, r) 152 gv_check_eq("T17-pure-prefix-first-diff-is-the-shorter-canonical-length" as *u8, r[GT_R_FIRSTDIFF], r[GT_R_CANB], ctr) 153 gv_check_eq("T17-pure-prefix-slice_prefix-reads-1" as *u8, gt_slice_prefix(r), 1, ctr) 154 gv_check_eq("T17-pure-prefix-reads-DIFFERS" as *u8, v17c, GT_V_DIFFERS, ctr) 155 // T18 a compound assignment is parsed STRUCTURALLY in the canonical form: `x*=a+b` is x=(x*(a+b)), and it is NOT the 156 // token-level expansion x=x*a+b (a different tree; measured on the hand MVS line `aP2.x*=1.+.08*w2` before this tooth existed) 157 let v18: i64 = g_cdiff("{x*=a+b;}" as *u8, "{x=(x*(a+b));}" as *u8, r) 158 gv_check_eq("T18-compound-assign-parses-structurally-IDENTICAL" as *u8, v18, GT_V_IDENTICAL, ctr) 159 let n18: i64 = g_cdiff("{x*=a+b;}" as *u8, "{x=x*a+b;}" as *u8, r) 160 gv_check_eq("neg-control-compound-assign-is-NOT-the-token-expansion-DIFFERS" as *u8, n18, GT_V_DIFFERS, ctr) 161 let v18b: i64 = g_cdiff("{aP2.z+=704.*w1;}" as *u8, "{aP2.z=(aP2.z+(704.0*w1));}" as *u8, r) 162 gv_check_eq("T18-compound-on-swizzle-lvalue-IDENTICAL" as *u8, v18b, GT_V_IDENTICAL, ctr) 163 let v18c: i64 = g_cdiff("{br/=nr;bd/=nr;}" as *u8, "{br=(br/nr);bd=(bd/nr);}" as *u8, r) 164 gv_check_eq("T18-two-compounds-in-sequence-IDENTICAL" as *u8, v18c, GT_V_IDENTICAL, ctr) 165 // T16 THE REAL SUBJECT: the hand MVS on the board canonicalises to itself, and canonicalising ADDED tokens (parentheses) 166 let lbm: *i64 = sys_mmap(16) as *i64 167 var mvs: *u8 = sys_read_file("buildroot/knowledge/compare/cast_mvs_hand.glsl" as *u8, lbm) 168 var mvs_root: i64 = 1 169 if (mvs as i64) == 0 { mvs = sys_read_file("knowledge/compare/cast_mvs_hand.glsl" as *u8, lbm); mvs_root = 2 } 170 var vm: i64 = 0 - 1 171 var mcan: i64 = 0 172 var mexp: i64 = 1 173 var mraw: i64 = 0 174 if (mvs as i64) != 0 { vm = gt_diff_canon(mvs, lbm[0], mvs, lbm[0], r); mcan = r[GT_R_CANA]; mexp = r[GT_R_EXPA]; mraw = r[GT_R_TOKA] } else { mvs_root = 0 } 175 gv_check("T16-hand-MVS-board-file-readable-from-the-nishihost-or-buildroot-root" as *u8, ((mvs as i64) != 0) as i64, ctr) 176 gv_check_eq("T16-hand-MVS-canonical-self-diff-IDENTICAL" as *u8, vm, GT_V_IDENTICAL, ctr) 177 gv_check("T16-hand-MVS-canonical-tokens-exceed-expanded (parentheses were added, never dropped)" as *u8, (mcan > mexp) as i64, ctr) 178 gv_kv("T1_tokens_a" as *u8, t1_tokens) 179 gv_kv("T1_expanded_a" as *u8, t1_expanded) 180 gv_kv("mvs_root" as *u8, mvs_root) 181 gv_kv("mvs_raw_tokens" as *u8, mraw) 182 gv_kv("mvs_expanded_tokens" as *u8, mexp) 183 gv_kv("mvs_canonical_tokens" as *u8, mcan) 184 return gv_verdict("nx_glsl_tokdiff_gate" as *u8, ctr, "the ruler the S12c accept rule is measured with, bitten in both directions" as *u8) 185}