code wiki / _hdl_build / nx_uiq_atree_lib.nx

nx_uiq_atree_lib.nx source

↩ module page · 533 lines · 23440 B

1// nx_uiq_atree_lib.nx -- F106b ARIA-tree snapshot + Zhang-Shasha tree edit distance (experiential). 2// SOTA axis (banked 07-21): ARIA-tree snapshots + ZSS TED = the deterministic STRUCTURAL regression 3// signal (Playwright aria-snapshot analog), computed sovereignly. A page becomes a role tree 4// (landmarks/headings/links/buttons/inputs/imgs/lists/tables/forms + explicit role= overrides, 5// names from aria-label > alt > inner text), rooted at a virtual document node; TED between two 6// trees = insert/delete/rename cost 1 (classic Zhang-Shasha keyroot DP). TED 0 = structurally 7// identical BY CONSTRUCTION; a removed nav link, a demoted heading, an inserted wrapper each = 1. 8// HONEST ENVELOPE: static source scan; script bodies masked; generic div/span skipped unless role=; 9// node cap 512 + depth cap 64 DECLARED (capped tree -> TED refused, never silently truncated). 10// license_tier: ORIGINAL genealogy: F106b; family nx_uiq_color/contrast/perf/console 11import "nx_uiq_console_lib.nx" 12 13const AT_CAP_NODES: i64 = 512 14const AT_CAP_DEPTH: i64 = 64 15const AT_S_ROLE: i64 = 16 16const AT_S_AUX: i64 = 528 17const AT_S_NOFF: i64 = 1040 18const AT_S_NLEN: i64 = 1552 19const AT_S_PAR: i64 = 2064 20const AT_SLOTS: i64 = 2576 21const AT_FIX_A: *u8 = "<header><h1>Site</h1></header><nav><a href=\"/x\">X</a><a href=\"/y\">Y</a></nav><main><section><h2>S</h2><img src=\"i.png\" alt=\"pic\"></section></main><footer></footer>" as *u8 22const AT_FIX_C: *u8 = "<header><h1>Site</h1></header><nav><a href=\"/x\">X</a></nav><main><section><h2>S</h2><img src=\"i.png\" alt=\"pic\"></section></main><footer></footer>" as *u8 23const AT_FIX_D: *u8 = "<header><h2>Site</h2></header><nav><a href=\"/x\">X</a><a href=\"/y\">Y</a></nav><main><section><h2>S</h2><img src=\"i.png\" alt=\"pic\"></section></main><footer></footer>" as *u8 24const AT_FIX_E: *u8 = "<header><h1>Site</h1></header><nav><a href=\"/x\">X</a><a href=\"/y\">Y</a></nav><main><article><section><h2>S</h2><img src=\"i.png\" alt=\"pic\"></section></article></main><footer></footer>" as *u8 25const AT_FIX_MASK2: *u8 = "<nav><a href=\"/x\">X</a></nav><script>let s='<nav><a href=\"/z\">Z</a></nav>'</script>" as *u8 26 27func at_arr(t: *i64, slot: i64) -> *i64 { 28 let b: i64 = t as i64 29 let o: i64 = slot*8 30 return (b+o) as *i64 31} 32 33func at_min3(a: i64, b: i64, c: i64) -> i64 { 34 var m: i64 = a 35 if b<m { m=b } 36 if c<m { m=c } 37 return m 38} 39 40// find attr value ` name="value"` inside [s,g); out[0]=off out[1]=len; returns 1/0 41func at_attr_val(mk: *u8, s: i64, g: i64, pat: *u8, out: *i64) -> i64 { 42 let o: i64 = cs_find_from(mk, g, s, pat) 43 if o<0 { return 0 } 44 let pl: i64 = cs_len(pat) 45 let vs: i64 = o+pl 46 var e: i64 = vs 47 var d: i64 = 0 48 while d==0 { if e>=g { d=1 } else { let c: i64=mk[e] as i64; if c==34 { d=1 } else { e=e+1 } } } 49 out[0]=vs 50 out[1]=e-vs 51 return 1 52} 53 54// exact tag compare: uiq_word_eq is PREFIX-based (lit exhausted = match) -- a bare "a" would 55// swallow article/aside and "li" would swallow <link>; length must match exactly. 56func at_tag_eq(mk: *u8, off: i64, len: i64, lit: *u8) -> i64 { 57 let ll: i64 = cs_len(lit) 58 if ll!=len { return 0 } 59 return uiq_word_eq(mk, off, len, lit) 60} 61 62// tag -> role id: 1 banner 2 nav 3 main 4 contentinfo 5 aside 6 region 7 article 8 heading(aux=lvl) 63// 9 link 10 button 11 input 12 img 13 table 14 list 15 listitem 16 form 17 dialog 18 combobox 64// 19 textarea 20 explicit-role. out[0]=role out[1]=aux out[2]=container(1/0) 65func at_tagrole(mk: *u8, toff: i64, tlen: i64, out: *i64) -> i64 { 66 out[0]=0 67 out[1]=0 68 out[2]=1 69 if at_tag_eq(mk,toff,tlen,"header" as *u8)==1 { out[0]=1; return 1 } 70 if at_tag_eq(mk,toff,tlen,"nav" as *u8)==1 { out[0]=2; return 1 } 71 if at_tag_eq(mk,toff,tlen,"main" as *u8)==1 { out[0]=3; return 1 } 72 if at_tag_eq(mk,toff,tlen,"footer" as *u8)==1 { out[0]=4; return 1 } 73 if at_tag_eq(mk,toff,tlen,"aside" as *u8)==1 { out[0]=5; return 1 } 74 if at_tag_eq(mk,toff,tlen,"section" as *u8)==1 { out[0]=6; return 1 } 75 if at_tag_eq(mk,toff,tlen,"article" as *u8)==1 { out[0]=7; return 1 } 76 if tlen==2 { 77 let c0: i64 = mk[toff] as i64 78 let c1: i64 = mk[toff+1] as i64 79 if c0==104 { if c1>=49 { if c1<=54 { out[0]=8; out[1]=c1-48; return 1 } } } 80 } 81 if at_tag_eq(mk,toff,tlen,"button" as *u8)==1 { out[0]=10; return 1 } 82 if at_tag_eq(mk,toff,tlen,"input" as *u8)==1 { out[0]=11; out[2]=0; return 1 } 83 if at_tag_eq(mk,toff,tlen,"img" as *u8)==1 { out[0]=12; out[2]=0; return 1 } 84 if at_tag_eq(mk,toff,tlen,"table" as *u8)==1 { out[0]=13; return 1 } 85 if at_tag_eq(mk,toff,tlen,"ul" as *u8)==1 { out[0]=14; return 1 } 86 if at_tag_eq(mk,toff,tlen,"ol" as *u8)==1 { out[0]=14; return 1 } 87 if at_tag_eq(mk,toff,tlen,"li" as *u8)==1 { out[0]=15; return 1 } 88 if at_tag_eq(mk,toff,tlen,"form" as *u8)==1 { out[0]=16; return 1 } 89 if at_tag_eq(mk,toff,tlen,"dialog" as *u8)==1 { out[0]=17; return 1 } 90 if at_tag_eq(mk,toff,tlen,"select" as *u8)==1 { out[0]=18; return 1 } 91 if at_tag_eq(mk,toff,tlen,"textarea" as *u8)==1 { out[0]=19; return 1 } 92 return 0 93} 94 95// build role tree from html buf into tree object t (mmap AT_SLOTS*8). returns node count. 96func at_build(buf: *u8, n: i64, t: *i64) -> i64 { 97 let mk: *u8 = sys_mmap(n+16) 98 cs_mask_scripts(buf, n, mk) 99 let role: *i64 = at_arr(t, AT_S_ROLE) 100 let aux: *i64 = at_arr(t, AT_S_AUX) 101 let noff: *i64 = at_arr(t, AT_S_NOFF) 102 let nlen: *i64 = at_arr(t, AT_S_NLEN) 103 let par: *i64 = at_arr(t, AT_S_PAR) 104 t[1]=0 105 t[2]=buf as i64 106 role[0]=0 107 aux[0]=0 108 noff[0]=0 109 nlen[0]=0 110 par[0]=0-1 111 var nn: i64 = 1 112 let stn: *i64 = sys_mmap(AT_CAP_DEPTH*8) as *i64 113 let sto: *i64 = sys_mmap(AT_CAP_DEPTH*8) as *i64 114 let stl: *i64 = sys_mmap(AT_CAP_DEPTH*8) as *i64 115 stn[0]=0 116 sto[0]=0 117 stl[0]=0 118 var sp: i64 = 1 119 let av: *i64 = sys_mmap(32) as *i64 120 let ro: *i64 = sys_mmap(32) as *i64 121 var i: i64 = 0 122 while i<n { 123 let c: i64 = mk[i] as i64 124 if c!=60 { i=i+1 } else { 125 if i+1>=n { i=i+1 } else { 126 let c1: i64 = mk[i+1] as i64 127 if c1==33 { 128 var isc: i64 = 0 129 if i+3<n { let c2: i64=mk[i+2] as i64; let c3: i64=mk[i+3] as i64; if c2==45 { if c3==45 { isc=1 } } } 130 if isc==1 { 131 let ce: i64 = cs_find_from(mk, n, i+4, "-->" as *u8) 132 if ce<0 { i=n } else { i=ce+3 } 133 } else { 134 var j: i64=i+2 135 var d: i64=0 136 while d==0 { if j>=n { d=1 } else { let cj: i64=mk[j] as i64; if cj==62 { d=1 } else { j=j+1 } } } 137 i=j+1 138 } 139 } else { 140 if c1==47 { 141 let ts: i64 = i+2 142 var e: i64 = ts 143 var d2: i64 = 0 144 while d2==0 { if e>=n { d2=1 } else { let ce2: i64=mk[e] as i64; let isn: i64=cs_namec(ce2); if isn==1 { e=e+1 } else { d2=1 } } } 145 let tl: i64 = e-ts 146 var j2: i64 = e 147 var d3: i64 = 0 148 while d3==0 { if j2>=n { d3=1 } else { let cj2: i64=mk[j2] as i64; if cj2==62 { d3=1 } else { j2=j2+1 } } } 149 var k: i64 = sp-1 150 var fnd: i64 = 0-1 151 while k>=1 { let sm: i64 = cs_span_eq(mk, sto[k], stl[k], ts, tl); if sm==1 { fnd=k; k=0 } else { k=k-1 } } 152 if fnd>=1 { sp=fnd } 153 i=j2+1 154 } else { 155 let isn0: i64 = cs_namec(c1) 156 if isn0==0 { i=i+1 } else { 157 let ts: i64 = i+1 158 var e: i64 = ts 159 var d2: i64 = 0 160 while d2==0 { if e>=n { d2=1 } else { let ce2: i64=mk[e] as i64; let isn: i64=cs_namec(ce2); if isn==1 { e=e+1 } else { d2=1 } } } 161 let tl: i64 = e-ts 162 var g: i64 = e 163 var d3: i64 = 0 164 while d3==0 { if g>=n { d3=1 } else { let cg: i64=mk[g] as i64; if cg==62 { d3=1 } else { g=g+1 } } } 165 ro[0]=0 166 ro[1]=0 167 ro[2]=1 168 let hasrole: i64 = at_attr_val(mk, e, g, " role=\"" as *u8, av) 169 if hasrole==1 { ro[0]=20; ro[1]=0; ro[2]=1 } else { let tr: i64 = at_tagrole(mk, ts, tl, ro); if tr==0 { ro[0]=0 } } 170 var rv: i64 = ro[0] 171 var isa: i64 = 0 172 if at_tag_eq(mk,ts,tl,"a" as *u8)==1 { isa=1 } 173 if isa==1 { 174 if hasrole==0 { 175 let hh: i64 = cs_find_from(mk, g, e, " href" as *u8) 176 if hh>=0 { rv=9; ro[1]=0; ro[2]=1 } else { rv=0 } 177 } 178 } 179 // CHROME-AX-CALIBRATED 2026-07-23 (seq632): a bare <section>/<form> is 180 // GENERIC in the real a11y tree -- region/form require an accessible NAME. 181 // And <header>/<footer> are banner/contentinfo ONLY at document scope; 182 // inside nav/main/aside/section/article the browser demotes them. 183 if hasrole==0 { 184 if rv==6 || rv==16 { 185 var named: i64 = 0 186 let l1: i64 = cs_find_from(mk, g, e, " aria-label=\"" as *u8) 187 if l1>=0 { named=1 } 188 let l2: i64 = cs_find_from(mk, g, e, " aria-labelledby=\"" as *u8) 189 if l2>=0 { named=1 } 190 let l3: i64 = cs_find_from(mk, g, e, " title=\"" as *u8) 191 if l3>=0 { named=1 } 192 if named==0 { rv=0 } 193 } 194 if rv==1 || rv==4 { 195 var scoped: i64 = 0 196 var k2: i64 = sp-1 197 while k2>=1 { 198 let an: i64 = stn[k2] 199 let ar: i64 = role[an] 200 if ar==2 || ar==3 || ar==5 || ar==6 || ar==7 { scoped=1; k2=0 } else { k2=k2-1 } 201 } 202 if scoped==1 { rv=0 } 203 } 204 } 205 if rv>0 { 206 var nmo: i64 = 0 207 var nml: i64 = 0 208 if hasrole==1 { nmo=av[0]; nml=av[1] } else { 209 let hal: i64 = at_attr_val(mk, e, g, " aria-label=\"" as *u8, av) 210 if hal==1 { nmo=av[0]; nml=av[1] } else { 211 if rv==12 { 212 let haa: i64 = at_attr_val(mk, e, g, " alt=\"" as *u8, av) 213 if haa==1 { nmo=av[0]; nml=av[1] } 214 } 215 if rv==8 || rv==9 || rv==10 { 216 var xs: i64 = g+1 217 var d4: i64 = 0 218 while d4==0 { if xs>=n { d4=1 } else { let cx: i64=mk[xs] as i64; if cx==32 || cx==10 || cx==13 || cx==9 { xs=xs+1 } else { d4=1 } } } 219 var xe: i64 = xs 220 var d5: i64 = 0 221 while d5==0 { if xe>=n { d5=1 } else { let cy: i64=mk[xe] as i64; if cy==60 { d5=1 } else { if xe-xs>=40 { d5=1 } else { xe=xe+1 } } } } 222 nmo=xs 223 nml=xe-xs 224 } 225 } 226 } 227 if nn<AT_CAP_NODES { 228 role[nn]=rv 229 aux[nn]=ro[1] 230 noff[nn]=nmo 231 nlen[nn]=nml 232 par[nn]=stn[sp-1] 233 if ro[2]==1 { if sp<AT_CAP_DEPTH { stn[sp]=nn; sto[sp]=ts; stl[sp]=tl; sp=sp+1 } } 234 nn=nn+1 235 } else { t[1]=1 } 236 } 237 i=g+1 238 } 239 } 240 } 241 } 242 } 243 } 244 t[0]=nn 245 return nn 246} 247 248func at_rolename(r: i64, a: i64) -> i64 { 249 if r==0 { uiq_w("document" as *u8); return 0 } 250 if r==1 { uiq_w("banner" as *u8); return 0 } 251 if r==2 { uiq_w("navigation" as *u8); return 0 } 252 if r==3 { uiq_w("main" as *u8); return 0 } 253 if r==4 { uiq_w("contentinfo" as *u8); return 0 } 254 if r==5 { uiq_w("complementary" as *u8); return 0 } 255 if r==6 { uiq_w("region" as *u8); return 0 } 256 if r==7 { uiq_w("article" as *u8); return 0 } 257 if r==8 { uiq_w("heading" as *u8); uiq_pn(a); return 0 } 258 if r==9 { uiq_w("link" as *u8); return 0 } 259 if r==10 { uiq_w("button" as *u8); return 0 } 260 if r==11 { uiq_w("input" as *u8); return 0 } 261 if r==12 { uiq_w("img" as *u8); return 0 } 262 if r==13 { uiq_w("table" as *u8); return 0 } 263 if r==14 { uiq_w("list" as *u8); return 0 } 264 if r==15 { uiq_w("listitem" as *u8); return 0 } 265 if r==16 { uiq_w("form" as *u8); return 0 } 266 if r==17 { uiq_w("dialog" as *u8); return 0 } 267 if r==18 { uiq_w("combobox" as *u8); return 0 } 268 if r==19 { uiq_w("textarea" as *u8); return 0 } 269 uiq_w("role" as *u8) 270 return 0 271} 272 273// print indented snapshot (skips the virtual root) 274func at_snap(t: *i64) -> i64 { 275 let nn: i64 = t[0] 276 let role: *i64 = at_arr(t, AT_S_ROLE) 277 let aux: *i64 = at_arr(t, AT_S_AUX) 278 let noff: *i64 = at_arr(t, AT_S_NOFF) 279 let nlen: *i64 = at_arr(t, AT_S_NLEN) 280 let par: *i64 = at_arr(t, AT_S_PAR) 281 let pb: *u8 = t[2] as *u8 282 var i: i64 = 1 283 while i<nn { 284 var d: i64 = 0 285 var p: i64 = par[i] 286 while p>0 { d=d+1; p=par[p] } 287 var k: i64 = 0 288 while k<d { uiq_w(" " as *u8); k=k+1 } 289 let r: i64 = role[i] 290 let a: i64 = aux[i] 291 at_rolename(r, a) 292 let nl: i64 = nlen[i] 293 if nl>0 { 294 uiq_w(" \"" as *u8) 295 let no: i64 = noff[i] 296 uiq_wslice(pb, no, nl) 297 uiq_w("\"" as *u8) 298 } 299 uiq_w("\n" as *u8) 300 i=i+1 301 } 302 return 0 303} 304 305func at_names_eq(ba: *u8, oa: i64, la: i64, bb: *u8, ob: i64, lb: i64) -> i64 { 306 if la!=lb { return 0 } 307 var k: i64 = 0 308 while k<la { let x: i64=ba[oa+k] as i64; let y: i64=bb[ob+k] as i64; if x!=y { return 0 } k=k+1 } 309 return 1 310} 311 312// label cost between node x of ta and node y of tb: 0 identical, 1 rename 313func at_lcost(ta: *i64, x: i64, tb: *i64, y: i64) -> i64 { 314 let ra: *i64 = at_arr(ta, AT_S_ROLE) 315 let rb: *i64 = at_arr(tb, AT_S_ROLE) 316 if ra[x]!=rb[y] { return 1 } 317 let aa: *i64 = at_arr(ta, AT_S_AUX) 318 let ab: *i64 = at_arr(tb, AT_S_AUX) 319 if aa[x]!=ab[y] { return 1 } 320 let noa: *i64 = at_arr(ta, AT_S_NOFF) 321 let nla: *i64 = at_arr(ta, AT_S_NLEN) 322 let nob: *i64 = at_arr(tb, AT_S_NOFF) 323 let nlb: *i64 = at_arr(tb, AT_S_NLEN) 324 let pa: *u8 = ta[2] as *u8 325 let pbb: *u8 = tb[2] as *u8 326 let eq: i64 = at_names_eq(pa, noa[x], nla[x], pbb, nob[y], nlb[y]) 327 if eq==1 { return 0 } 328 return 1 329} 330 331// compute postorder po[], node->po poidx[], leftmost-leaf lpo[] (po coords), keyroot kr[] flags 332func at_order(t: *i64, po: *i64, poidx: *i64, lpo: *i64, kr: *i64) -> i64 { 333 let nn: i64 = t[0] 334 let par: *i64 = at_arr(t, AT_S_PAR) 335 let kcnt: *i64 = sys_mmap(nn*8+16) as *i64 336 let koff: *i64 = sys_mmap(nn*8+16) as *i64 337 let kfil: *i64 = sys_mmap(nn*8+16) as *i64 338 let kids: *i64 = sys_mmap(nn*8+16) as *i64 339 var i: i64 = 0 340 while i<nn { kcnt[i]=0; i=i+1 } 341 i=1 342 while i<nn { let p: i64=par[i]; kcnt[p]=kcnt[p]+1; i=i+1 } 343 koff[0]=0 344 i=1 345 while i<nn { koff[i]=koff[i-1]+kcnt[i-1]; i=i+1 } 346 i=0 347 while i<nn { kfil[i]=koff[i]; i=i+1 } 348 i=1 349 while i<nn { let p2: i64=par[i]; let s: i64=kfil[p2]; kids[s]=i; kfil[p2]=s+1; i=i+1 } 350 let stn: *i64 = sys_mmap(nn*8+16) as *i64 351 let stc: *i64 = sys_mmap(nn*8+16) as *i64 352 stn[0]=0 353 stc[0]=0 354 var sp: i64 = 0 355 var pn: i64 = 0 356 while sp>=0 { 357 let nd: i64 = stn[sp] 358 let cu: i64 = stc[sp] 359 if cu<kcnt[nd] { 360 stc[sp]=cu+1 361 let ko: i64 = koff[nd] 362 let ch: i64 = kids[ko+cu] 363 sp=sp+1 364 stn[sp]=ch 365 stc[sp]=0 366 } else { 367 po[pn]=nd 368 poidx[nd]=pn 369 pn=pn+1 370 sp=sp-1 371 } 372 } 373 var k: i64 = 0 374 while k<nn { 375 let nd2: i64 = po[k] 376 if kcnt[nd2]==0 { lpo[k]=k } else { 377 let ko2: i64 = koff[nd2] 378 let fc: i64 = kids[ko2] 379 let fpi: i64 = poidx[fc] 380 lpo[k]=lpo[fpi] 381 } 382 k=k+1 383 } 384 let seen: *i64 = sys_mmap(nn*8+16) as *i64 385 var q: i64 = nn-1 386 while q>=0 { 387 let lv: i64 = lpo[q] 388 if seen[lv]==0 { kr[q]=1; seen[lv]=1 } else { kr[q]=0 } 389 q=q-1 390 } 391 return pn 392} 393 394// Zhang-Shasha TED. returns edit distance, or -1 if either tree hit the node cap. 395func at_ted(ta: *i64, tb: *i64) -> i64 { 396 if ta[1]==1 { return 0-1 } 397 if tb[1]==1 { return 0-1 } 398 let na: i64 = ta[0] 399 let nb: i64 = tb[0] 400 let poa: *i64 = sys_mmap(na*8+16) as *i64 401 let pia: *i64 = sys_mmap(na*8+16) as *i64 402 let la: *i64 = sys_mmap(na*8+16) as *i64 403 let ka: *i64 = sys_mmap(na*8+16) as *i64 404 let pob: *i64 = sys_mmap(nb*8+16) as *i64 405 let pib: *i64 = sys_mmap(nb*8+16) as *i64 406 let lb: *i64 = sys_mmap(nb*8+16) as *i64 407 let kb: *i64 = sys_mmap(nb*8+16) as *i64 408 at_order(ta, poa, pia, la, ka) 409 at_order(tb, pob, pib, lb, kb) 410 let W: i64 = nb+2 411 let fd: *i64 = sys_mmap((na+2)*W*8+16) as *i64 412 let td: *i64 = sys_mmap(na*nb*8+16) as *i64 413 var ki: i64 = 0 414 while ki<na { 415 if ka[ki]==1 { 416 var kj: i64 = 0 417 while kj<nb { 418 if kb[kj]==1 { 419 let lia: i64 = la[ki] 420 let ljb: i64 = lb[kj] 421 fd[0]=0 422 var i: i64 = lia 423 while i<=ki { let r1: i64=(i-lia+1)*W; let r0: i64=(i-lia)*W; fd[r1]=fd[r0]+1; i=i+1 } 424 var j: i64 = ljb 425 while j<=kj { let c1: i64=j-ljb+1; fd[c1]=fd[c1-1]+1; j=j+1 } 426 i=lia 427 while i<=ki { 428 let ai: i64 = i-lia+1 429 j=ljb 430 while j<=kj { 431 let bj: i64 = j-ljb+1 432 var both: i64 = 0 433 if la[i]==lia { if lb[j]==ljb { both=1 } } 434 if both==1 { 435 let nxa: i64 = poa[i] 436 let nxb: i64 = pob[j] 437 let cc: i64 = at_lcost(ta, nxa, tb, nxb) 438 let i1: i64 = (ai-1)*W+bj 439 let i2: i64 = ai*W+bj-1 440 let i3: i64 = (ai-1)*W+bj-1 441 let d1: i64 = fd[i1]+1 442 let d2: i64 = fd[i2]+1 443 let d3: i64 = fd[i3]+cc 444 let mv: i64 = at_min3(d1, d2, d3) 445 let i0: i64 = ai*W+bj 446 fd[i0]=mv 447 let ti: i64 = i*nb+j 448 td[ti]=mv 449 } else { 450 let pai: i64 = la[i]-lia 451 let pbj: i64 = lb[j]-ljb 452 let ib: i64 = pai*W+pbj 453 let base0: i64 = fd[ib] 454 let ti: i64 = i*nb+j 455 let tdv: i64 = td[ti] 456 let i1: i64 = (ai-1)*W+bj 457 let i2: i64 = ai*W+bj-1 458 let d1: i64 = fd[i1]+1 459 let d2: i64 = fd[i2]+1 460 let d3: i64 = base0+tdv 461 let mv: i64 = at_min3(d1, d2, d3) 462 let i0: i64 = ai*W+bj 463 fd[i0]=mv 464 } 465 j=j+1 466 } 467 i=i+1 468 } 469 } 470 kj=kj+1 471 } 472 } 473 ki=ki+1 474 } 475 let fin: i64 = (na-1)*nb + nb-1 476 return td[fin] 477} 478 479// build both trees from html buffers and return TED (-1 = capped) 480func at_ted_html(ba: *u8, na: i64, bb: *u8, nb: i64) -> i64 { 481 let ta: *i64 = sys_mmap(AT_SLOTS*8) as *i64 482 let tb: *i64 = sys_mmap(AT_SLOTS*8) as *i64 483 at_build(ba, na, ta) 484 at_build(bb, nb, tb) 485 return at_ted(ta, tb) 486} 487 488// selftest: exact node counts + TED oracle 0/1/1/1 + symmetry + script-mask. 0 = GREEN. 489func at_selftest() -> i64 { 490 var f: i64 = 0 491 let fa: *u8 = AT_FIX_A 492 let fal: i64 = cs_len(fa) 493 let ta: *i64 = sys_mmap(AT_SLOTS*8) as *i64 494 let nA: i64 = at_build(fa, fal, ta) 495 if nA!=10 { f=f+1 } 496 let lab: *u8 = "<section aria-label=\"L\"><h2>S</h2></section>" as *u8 497 let labl: i64 = cs_len(lab) 498 let tl2: *i64 = sys_mmap(AT_SLOTS*8) as *i64 499 let nL: i64 = at_build(lab, labl, tl2) 500 if nL!=3 { f=f+1 } 501 let bare: *u8 = "<section><h2>S</h2></section>" as *u8 502 let barel: i64 = cs_len(bare) 503 let tb2: *i64 = sys_mmap(AT_SLOTS*8) as *i64 504 let nB: i64 = at_build(bare, barel, tb2) 505 if nB!=2 { f=f+1 } 506 let scp: *u8 = "<article><footer>x</footer></article>" as *u8 507 let scpl: i64 = cs_len(scp) 508 let tc2: *i64 = sys_mmap(AT_SLOTS*8) as *i64 509 let nC2: i64 = at_build(scp, scpl, tc2) 510 if nC2!=2 { f=f+1 } 511 let t0: i64 = at_ted_html(fa, fal, fa, fal) 512 if t0!=0 { f=f+1 } 513 let fc: *u8 = AT_FIX_C 514 let fcl: i64 = cs_len(fc) 515 let t1: i64 = at_ted_html(fa, fal, fc, fcl) 516 if t1!=1 { f=f+1 } 517 let t1s: i64 = at_ted_html(fc, fcl, fa, fal) 518 if t1s!=1 { f=f+1 } 519 let fdx: *u8 = AT_FIX_D 520 let fdl: i64 = cs_len(fdx) 521 let t2: i64 = at_ted_html(fa, fal, fdx, fdl) 522 if t2!=1 { f=f+1 } 523 let fe: *u8 = AT_FIX_E 524 let fel: i64 = cs_len(fe) 525 let t3: i64 = at_ted_html(fa, fal, fe, fel) 526 if t3!=1 { f=f+1 } 527 let fm: *u8 = AT_FIX_MASK2 528 let fml: i64 = cs_len(fm) 529 let tm: *i64 = sys_mmap(AT_SLOTS*8) as *i64 530 let nM: i64 = at_build(fm, fml, tm) 531 if nM!=3 { f=f+1 } 532 return f 533}