code wiki / _hdl_build / nx_fold_punct_gate.nx
nx_fold_punct_gate.nx source
↩ module page · 59 lines · 3572 B
1// nx_fold_punct_gate.nx -- regression gate for the browser text pipeline: HTML entity DECODE -> UTF-8
2// -> ASCII FOLD, the exact path br_draw_fb paints. Locks the 2026-07-10 fix that made typographic
3// punctuation (— · ’ › … arrows) render instead of vanishing to blank
4// gaps in the 5x7 font, WITHOUT regressing accent-fold (é->e) or ASCII passthrough. Found by dogfooding
5// the Nishi browser on our own /compare pages. license_tier: ORIGINAL expect_exit: 0
6import "nx_html_entities.nx"
7
8func fg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
9func fg_check(pass: i64, label: *u8, fails: *i64) -> i64 {
10 fg_w(" " as *u8); fg_w(label); fg_w(": " as *u8)
11 if pass==1 { fg_w("PASS\n" as *u8) } else { fg_w("FAIL\n" as *u8); fails[0]=fails[0]+1 }
12 return 0
13}
14// decode src (an entity-bearing string) then fold to ASCII; compare to want. returns 1 match.
15func fg_pipe_eq(src: *u8, slen: i64, want: *u8) -> i64 {
16 let dec: *u8 = sys_mmap(1024)
17 let fold: *u8 = sys_mmap(1024)
18 let dn: i64 = nx_html_decode_entities(src, 0, slen, dec, 1024)
19 let fn: i64 = nx_fold_ascii(dec, 0, dn, fold, 1024)
20 var wl: i64 = 0
21 while want[wl]!=(0 as u8) { wl=wl+1 }
22 if fn != wl { return 0 }
23 var i: i64=0
24 while i<fn { if fold[i]!=want[i] { return 0 } i=i+1 }
25 return 1
26}
27
28func main() -> i64 {
29 let fails: *i64 = sys_mmap(16) as *i64
30 fails[0]=0
31 fg_w("=== nx_fold_punct_gate -- entity-decode -> ASCII-fold (the browser paint pipeline) ===\n" as *u8)
32
33 // the FIX: typographic punctuation now folds to a readable ASCII byte (was blank)
34 fg_check(fg_pipe_eq("a—b" as *u8, 9, "a-b" as *u8), "T1 — -> '-' (was blank gap)" as *u8, fails)
35 fg_check(fg_pipe_eq("a·b" as *u8, 10, "a*b" as *u8), "T2 · -> '*'" as *u8, fails)
36 fg_check(fg_pipe_eq("it’s" as *u8, 10, "it's" as *u8), "T3 ’ -> apostrophe" as *u8, fails)
37 fg_check(fg_pipe_eq("A›B" as *u8, 10, "A>B" as *u8), "T4 › -> '>' (was undecoded literal)" as *u8, fails)
38 fg_check(fg_pipe_eq("x…" as *u8, 9, "x." as *u8), "T5 … -> '.'" as *u8, fails)
39 fg_check(fg_pipe_eq("←→" as *u8, 12, "<>" as *u8), "T6 arrows ←→ -> '<' '>'" as *u8, fails)
40 fg_check(fg_pipe_eq("“hi”" as *u8, 16, "\x22hi\x22" as *u8), "T7 curly quotes -> straight quotes" as *u8, fails)
41
42 // NO REGRESSION: accents still fold to base letter; ASCII passes through
43 fg_check(fg_pipe_eq("café" as *u8, 11, "cafe" as *u8), "T8 é -> 'e' (accent fold intact)" as *u8, fails)
44 fg_check(fg_pipe_eq("plain text" as *u8, 10, "plain text" as *u8), "T9 ASCII passthrough unchanged" as *u8, fails)
45 fg_check(fg_pipe_eq("a&b<c" as *u8, 12, "a&b<c" as *u8), "T10 core entities &< still decode" as *u8, fails)
46
47 // NEG-CONTROL: non-Latin (Cyrillic UTF-8) cleanly SKIPS (no byte-gaps), not garbage
48 let cyr: *u8 = sys_mmap(16)
49 cyr[0]=0xD0 as u8; cyr[1]=0xBF as u8; cyr[2]=0xD0 as u8; cyr[3]=0xB0 as u8 // "па" (2 Cyrillic cps)
50 let fold: *u8 = sys_mmap(64)
51 let fn: i64 = nx_fold_ascii(cyr, 0, 4, fold, 64)
52 fg_check((fn==0) as i64, "T11 NEG Cyrillic folds to empty (skipped clean, no blank-gap bytes)" as *u8, fails)
53
54 fg_w(" fails=" as *u8)
55 if fails[0]==0 { fg_w("0\nVERDICT: GREEN (punctuation renders; accents + ASCII + core entities intact; non-Latin skips clean)\n" as *u8); sys_exit(0) }
56 fg_w("nonzero\nVERDICT: RED\n" as *u8)
57 sys_exit(1)
58 return 1
59}