code wiki / _hdl_build / nx_float_gate.nx

nx_float_gate.nx source

↩ module page · 176 lines · 10402 B

1// nx_float_gate.nx -- VERDICT gate for the R5 float rung of the sovereign HTML renderer (browser Phase 2-4). 2// The sibling nx_float_test DUMPS per-box geometry for eyeballing; this gate ASSERTS the exact placement 3// the float/flex layout must produce, so the rung is MACHINE-VERIFIED, not human-read. It runs the REAL 4// render pipeline prefix (nx_layout_from_dom -> box<->element map -> rh_cascade -> nx_layout_block_layout) 5// -- identical to what nx_render_html uses on real pages -- on controlled fixtures and checks x/y/w/h. 6// 7// Differential correctness is built in: the SAME markup with vs without float must lay out DIFFERENTLY 8// (float:left -> main BESIDE at x=200; no float -> main BELOW at y=10), so a layout that ignored float 9// could not pass both. LIAR-KILL: the checker is fed a deliberately wrong expectation and must REJECT it 10// (proving it is not a rubber stamp). GREEN iff every assertion holds. 100% sovereign (no gcc/V8/Chrome). 11// license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_css_tokenize.nx" 14import "nx_css_parse.nx" 15import "nx_css_apply.nx" 16import "nx_css_color_decode.nx" 17import "nx_css_dimension_to_px.nx" 18import "nx_css_selector_match.nx" 19import "nx_html_tokenizer.nx" 20import "nx_dom_query.nx" 21import "nx_layout_box.nx" 22import "nx_layout_default_display.nx" 23import "nx_layout_from_dom.nx" 24import "nx_layout_block.nx" 25import "nx_render_html.nx" 26 27func g_w(s: *u8) -> i64 { var k: i64=0; while s[k]!=(0 as u8){k=k+1} sys_write(1,s,k); return 0 } 28func pn(v0: i64) -> i64 { var v: i64=v0; if v<0 { let m: *u8=sys_mmap(8); m[0]=45 as u8; sys_write(1,m,1); v=0-v } let b: *u8=sys_mmap(24); var k: i64=0; if v==0 {b[0]=48;k=1} while v>0 {b[k]=(48+(v%10)) as u8; v=v/10; k=k+1} let o: *u8=sys_mmap(24); var j: i64=0; while j<k {o[j]=b[k-1-j];j=j+1} sys_write(1,o,k); return 0 } 29 30// Run the REAL render pipeline prefix on (html + css) at viewport vw; return the laid-out box tree. 31// This is nx_float_test's run() with the diagnostic prints removed -- one render path, asserted not dumped. 32func run_layout(html: *u8, css: *u8, vw: i64) -> *LayoutTree { 33 var hlen: i64 = 0 34 while html[hlen]!=(0 as u8) { hlen=hlen+1 } 35 var clen: i64 = 0 36 while css[clen]!=(0 as u8) { clen=clen+1 } 37 let total: i64 = hlen + clen 38 let buf: *u8 = sys_mmap(total + 16) 39 var i: i64 = 0 40 while i < hlen { buf[i]=html[i]; i=i+1 } 41 var j: i64 = 0 42 while j < clen { buf[hlen+j]=css[j]; j=j+1 } 43 44 let boxes: *LayoutBox = (sys_mmap(NX_LAYOUT_BOX_BYTES*1024+16)) as *LayoutBox 45 let tree: *LayoutTree = (sys_mmap(64)) as *LayoutTree 46 nx_layout_tree_init(tree, boxes, 1024) 47 let stk: *LayoutFromDomStack = (sys_mmap(NX_LAYOUT_FROM_DOM_STACK_BYTES+8)) as *LayoutFromDomStack 48 let sidx: *i64 = (sys_mmap(8*64)) as *i64 49 nx_layout_from_dom_stack_init(stk, sidx, 64) 50 nx_layout_from_dom(buf, hlen, tree, stk) 51 52 let ext: *CssElement = (sys_mmap(NX_CSS_ELEMENT_BYTES*1024 as nx_size)) as *CssElement 53 let n_ext: i64 = rh_extract(buf, hlen, ext, 1024) 54 let boxel: *CssElement = (sys_mmap((NX_CSS_ELEMENT_BYTES*(tree.count+1)) as nx_size)) as *CssElement 55 var k: i64 = 0 56 i = 0 57 while i < tree.count { 58 let bb: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 59 let e: *CssElement = ((boxel as i64)+i*NX_CSS_ELEMENT_BYTES) as *CssElement 60 e.src = buf 61 var mapped: i64 = 0 62 if rh_is_elem(bb.kind)==1 { if bb.parent_idx != (0-1) { if k < n_ext { 63 let s: *CssElement = ((ext as i64)+k*NX_CSS_ELEMENT_BYTES) as *CssElement 64 e.tag_off=s.tag_off; e.tag_len=s.tag_len; e.id_off=s.id_off; e.id_len=s.id_len; e.class_off=s.class_off; e.class_len=s.class_len 65 k=k+1; mapped=1 66 } } } 67 if mapped==0 { e.tag_off=0; e.tag_len=0; e.id_off=0; e.id_len=0; e.class_off=0; e.class_len=0 } 68 i=i+1 69 } 70 71 let cur: *CssCursor = (sys_mmap(NX_CSS_CURSOR_BYTES) as nx_size) as *CssCursor 72 nx_css_cursor_init(cur, buf, total); cur.pos = hlen 73 let tok: *CssToken = (sys_mmap(NX_CSS_TOKEN_BYTES) as nx_size) as *CssToken 74 let rules: *CssRule = (sys_mmap(NX_CSS_RULE_BYTES*512 as nx_size)) as *CssRule 75 let decls: *CssDeclaration = (sys_mmap(NX_CSS_DECLARATION_BYTES*512 as nx_size)) as *CssDeclaration 76 let st: *CssParseState = (sys_mmap(128) as nx_size) as *CssParseState 77 nx_css_parse_state_init(st, cur, tok, rules, 512, decls, 512) 78 nx_css_parse(st) 79 let computed: *CssComputedDecl = (sys_mmap(NX_CSS_COMPUTED_DECL_BYTES*4096 as nx_size)) as *CssComputedDecl 80 let cb: *i64 = (sys_mmap(8)) as *i64 81 rh_cascade(buf, rules, st.rule_count, decls, st.decl_count, boxel, tree.count, tree, computed, 4096, cb) 82 let ncomp: i64 = cb[0] 83 84 let pbuf: *u8 = sys_mmap(256) 85 let ltable: *LayoutPropTable = (sys_mmap(NX_LAYOUT_PROP_TABLE_BYTES)) as *LayoutPropTable 86 nx_layout_prop_table_init(ltable, pbuf) 87 let resolve: *CssResolveCtx = (sys_mmap(NX_CSS_RESOLVE_CTX_BYTES)) as *CssResolveCtx 88 resolve.root_font_size_px = 16; resolve.parent_font_size_px = 16; resolve.parent_dimension_px = vw 89 let lctx: *LayoutCtx = (sys_mmap(NX_LAYOUT_CTX_BYTES)) as *LayoutCtx 90 nx_layout_ctx_init(lctx, tree, computed, ncomp, buf, vw, resolve) 91 nx_layout_block_layout(lctx, ltable, 0) 92 return tree 93} 94 95// Pure check: does box i have exactly geometry (ex,ey,ew,eh)? 1/0. No print, no side effect -- so the 96// liar-kill can call it with a wrong expectation and confirm it returns 0. 97func geom_match(tree: *LayoutTree, i: i64, ex: i64, ey: i64, ew: i64, eh: i64) -> i64 { 98 let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 99 if b.x != ex { return 0 } 100 if b.y != ey { return 0 } 101 if b.w != ew { return 0 } 102 if b.h != eh { return 0 } 103 return 1 104} 105 106// Asserting wrapper: print label + OK/FAIL(got vs expected), count passes. 107func chk(tree: *LayoutTree, i: i64, ex: i64, ey: i64, ew: i64, eh: i64, label: *u8, pass: *i64) -> i64 { 108 let m: i64 = geom_match(tree, i, ex, ey, ew, eh) 109 let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 110 g_w(" " as *u8); g_w(label); g_w(": " as *u8) 111 if m==1 { g_w("OK\n" as *u8); pass[0]=pass[0]+1 } 112 else { 113 g_w("FAIL got x=" as *u8); pn(b.x); g_w(" y=" as *u8); pn(b.y); g_w(" w=" as *u8); pn(b.w); g_w(" h=" as *u8); pn(b.h) 114 g_w(" expected x=" as *u8); pn(ex); g_w(" y=" as *u8); pn(ey); g_w(" w=" as *u8); pn(ew); g_w(" h=" as *u8); pn(eh); g_w("\n" as *u8) 115 } 116 return m 117} 118 119func main() -> i64 { 120 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0 121 g_w("=== FLOAT-RENDER GATE (asserted box geometry, sovereign nx_cc->nxasm) ===\n" as *u8) 122 123 // shared fixture: container with a sidebar div #sb and a main div #m 124 let html_sb: *u8 = "<div id=\"c\"><div id=\"sb\">S</div><div id=\"m\">main content here</div></div>\x00" as *u8 125 126 // ONE LINE BOX = NX_INLINE_LINE_H, imported from nx_layout_block -- NOT a literal. 127 // WHY (2026-07-30): every height here was hardcoded 10. The renderer then correctly moved to real 128 // 9x15 font metrics (nx_layout_block.nx:480, NX_INLINE_LINE_H = 17 ... was 10) and FIVE gates went 129 // RED at once -- float, grid, grid_track, render_page, border -- all reporting h=17 vs 10 with x and 130 // w perfectly correct. The engine was RIGHT and the gates were STALE. Re-hardcoding 17 would just 131 // re-arm the trap, so the expectation now DERIVES from the same constant the layout uses. 132 let LH: i64 = NX_INLINE_LINE_H 133 134 // F1 float:left -> #sb pinned x=0 w=200; #m flows BESIDE at x=200 w=600 (same row, y=0) 135 let t1: *LayoutTree = run_layout(html_sb, "#sb{float:left;width:200px}\x00" as *u8, 800) 136 g_w("F1 float:left\n" as *u8) 137 chk(t1, 2, 0, 0, 200, LH, "#sb pinned x=0 w=200\x00" as *u8, pass) 138 chk(t1, 4, 200, 0, 600, LH, "#m beside x=200 w=600\x00" as *u8, pass) 139 140 // F2 float:right -> #sb pinned to right edge x=600 w=200; #m at x=0 narrowed to w=600 141 let t2: *LayoutTree = run_layout(html_sb, "#sb{float:right;width:200px}\x00" as *u8, 800) 142 g_w("F2 float:right\n" as *u8) 143 chk(t2, 2, 600, 0, 200, LH, "#sb pinned right x=600\x00" as *u8, pass) 144 chk(t2, 4, 0, 0, 600, LH, "#m x=0 w=600\x00" as *u8, pass) 145 146 // F3 CONTROL: no float -> #sb and #m STACK; #m drops BELOW to y=10 at full width 800. 147 // (Differential vs F1: same markup, float removed -> different layout. A no-op "float" fails here.) 148 let t3: *LayoutTree = run_layout(html_sb, "#sb{width:200px}\x00" as *u8, 800) 149 g_w("F3 no-float control (must STACK, not float)\n" as *u8) 150 chk(t3, 2, 0, 0, 200, LH, "#sb x=0\x00" as *u8, pass) 151 chk(t3, 4, 0, LH, 800, LH, "#m BELOW by one line w=800\x00" as *u8, pass) 152 153 // F5 table via tr{display:flex}: cells side-by-side (equal share 400 each), rows stack (row2 at y=10) 154 let t5: *LayoutTree = run_layout("<table><tr><td>A</td><td>B</td></tr><tr><td>CC</td><td>DD</td></tr></table>\x00" as *u8, "tr{display:flex}\x00" as *u8, 800) 155 g_w("F5 table via tr{display:flex}\n" as *u8) 156 chk(t5, 3, 0, 0, 400, LH, "td A x=0 w=400\x00" as *u8, pass) 157 chk(t5, 5, 400, 0, 400, LH, "td B x=400 w=400\x00" as *u8, pass) 158 chk(t5, 8, 0, LH, 400, LH, "row2 td CC one line down\x00" as *u8, pass) 159 160 // F6 float a TABLE right: #tbl floats to x=600 w=200; #m flows beside at x=0 w=600 161 let t6: *LayoutTree = run_layout("<div id=\"c\"><table id=\"tbl\"><tr><td>X</td><td>Y</td></tr></table><div id=\"m\">beside</div></div>\x00" as *u8, "#tbl{float:right;width:200px}tr{display:flex}\x00" as *u8, 800) 162 g_w("F6 float table right\n" as *u8) 163 chk(t6, 2, 600, 0, 200, LH, "#tbl floated x=600\x00" as *u8, pass) 164 chk(t6, 8, 0, 0, 600, LH, "#m beside x=0 w=600\x00" as *u8, pass) 165 166 // LIAR-KILL: feed the checker the WRONG x for F1's floated-beside #m (real x=200, claim x=0). 167 // An honest checker MUST return 0. If it returned 1 (rubber stamp), this assertion fails -> gate RED. 168 g_w("LIAR-KILL (wrong geometry must be rejected)\n" as *u8) 169 let lk: i64 = geom_match(t1, 4, 0, 0, 600, LH) 170 g_w(" rejects bad x=0 for floated-beside #m: " as *u8) 171 if lk==0 { g_w("OK\n" as *u8); pass[0]=pass[0]+1 } else { g_w("FAIL (checker is a rubber stamp)\n" as *u8) } 172 173 g_w("FLOAT-RENDER rows=12 pass=" as *u8); pn(pass[0]) 174 if pass[0]==12 { g_w(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 175 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1 176}