code wiki / _hdl_build / nx_grid_track_gate.nx

nx_grid_track_gate.nx source

↩ module page · 162 lines · 9262 B

1// nx_grid_track_gate.nx -- VERDICT gate for GRID rung 2: PER-TRACK sizing (px fixed + fr flexible share 2// of leftover) + column-gap / row-gap / gap. Runs the REAL render pipeline prefix on controlled fixtures 3// and ASSERTS exact box geometry (measured via nx_grid_test). Proves: mixed `200px 1fr 1fr` (fixed + 4// fr); weighted `1fr 2fr`; `column-gap`; `gap` shorthand with row wrap (row-gap offsets the 2nd row); 5// `repeat(N, 150px)`. LIAR-KILL: a wrong expectation must be rejected. GREEN iff all hold. Also exercises 6// the CSS multi-token value capture (grid-template-columns + the gap properties). 100% sovereign. 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_css_tokenize.nx" 10import "nx_css_parse.nx" 11import "nx_css_apply.nx" 12import "nx_css_color_decode.nx" 13import "nx_css_dimension_to_px.nx" 14import "nx_css_selector_match.nx" 15import "nx_html_tokenizer.nx" 16import "nx_dom_query.nx" 17import "nx_layout_box.nx" 18import "nx_layout_default_display.nx" 19import "nx_layout_from_dom.nx" 20import "nx_layout_block.nx" 21import "nx_render_html.nx" 22 23func 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 } 24func 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 } 25 26func run_layout(html: *u8, css: *u8, vw: i64) -> *LayoutTree { 27 var hlen: i64 = 0 28 while html[hlen]!=(0 as u8) { hlen=hlen+1 } 29 var clen: i64 = 0 30 while css[clen]!=(0 as u8) { clen=clen+1 } 31 let total: i64 = hlen + clen 32 let buf: *u8 = sys_mmap(total + 16) 33 var i: i64 = 0 34 while i < hlen { buf[i]=html[i]; i=i+1 } 35 var j: i64 = 0 36 while j < clen { buf[hlen+j]=css[j]; j=j+1 } 37 38 let boxes: *LayoutBox = (sys_mmap(NX_LAYOUT_BOX_BYTES*1024+16)) as *LayoutBox 39 let tree: *LayoutTree = (sys_mmap(64)) as *LayoutTree 40 nx_layout_tree_init(tree, boxes, 1024) 41 let stk: *LayoutFromDomStack = (sys_mmap(NX_LAYOUT_FROM_DOM_STACK_BYTES+8)) as *LayoutFromDomStack 42 let sidx: *i64 = (sys_mmap(8*64)) as *i64 43 nx_layout_from_dom_stack_init(stk, sidx, 64) 44 nx_layout_from_dom(buf, hlen, tree, stk) 45 46 let ext: *CssElement = (sys_mmap(NX_CSS_ELEMENT_BYTES*1024 as nx_size)) as *CssElement 47 let n_ext: i64 = rh_extract(buf, hlen, ext, 1024) 48 let boxel: *CssElement = (sys_mmap((NX_CSS_ELEMENT_BYTES*(tree.count+1)) as nx_size)) as *CssElement 49 var k: i64 = 0 50 i = 0 51 while i < tree.count { 52 let bb: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 53 let e: *CssElement = ((boxel as i64)+i*NX_CSS_ELEMENT_BYTES) as *CssElement 54 e.src = buf 55 var mapped: i64 = 0 56 if rh_is_elem(bb.kind)==1 { if bb.parent_idx != (0-1) { if k < n_ext { 57 let s: *CssElement = ((ext as i64)+k*NX_CSS_ELEMENT_BYTES) as *CssElement 58 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 59 k=k+1; mapped=1 60 } } } 61 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 } 62 i=i+1 63 } 64 65 let cur: *CssCursor = (sys_mmap(NX_CSS_CURSOR_BYTES) as nx_size) as *CssCursor 66 nx_css_cursor_init(cur, buf, total); cur.pos = hlen 67 let tok: *CssToken = (sys_mmap(NX_CSS_TOKEN_BYTES) as nx_size) as *CssToken 68 let rules: *CssRule = (sys_mmap(NX_CSS_RULE_BYTES*512 as nx_size)) as *CssRule 69 let decls: *CssDeclaration = (sys_mmap(NX_CSS_DECLARATION_BYTES*512 as nx_size)) as *CssDeclaration 70 let st: *CssParseState = (sys_mmap(128) as nx_size) as *CssParseState 71 nx_css_parse_state_init(st, cur, tok, rules, 512, decls, 512) 72 nx_css_parse(st) 73 let computed: *CssComputedDecl = (sys_mmap(NX_CSS_COMPUTED_DECL_BYTES*4096 as nx_size)) as *CssComputedDecl 74 let cb: *i64 = (sys_mmap(8)) as *i64 75 rh_cascade(buf, rules, st.rule_count, decls, st.decl_count, boxel, tree.count, tree, computed, 4096, cb) 76 let ncomp: i64 = cb[0] 77 78 let pbuf: *u8 = sys_mmap(256) 79 let ltable: *LayoutPropTable = (sys_mmap(NX_LAYOUT_PROP_TABLE_BYTES)) as *LayoutPropTable 80 nx_layout_prop_table_init(ltable, pbuf) 81 let resolve: *CssResolveCtx = (sys_mmap(NX_CSS_RESOLVE_CTX_BYTES)) as *CssResolveCtx 82 resolve.root_font_size_px = 16; resolve.parent_font_size_px = 16; resolve.parent_dimension_px = vw 83 let lctx: *LayoutCtx = (sys_mmap(NX_LAYOUT_CTX_BYTES)) as *LayoutCtx 84 nx_layout_ctx_init(lctx, tree, computed, ncomp, buf, vw, resolve) 85 nx_layout_block_layout(lctx, ltable, 0) 86 return tree 87} 88 89func geom_match(tree: *LayoutTree, i: i64, ex: i64, ey: i64, ew: i64, eh: i64) -> i64 { 90 let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 91 if b.x != ex { return 0 } 92 if b.y != ey { return 0 } 93 if b.w != ew { return 0 } 94 if b.h != eh { return 0 } 95 return 1 96} 97func chk(tree: *LayoutTree, i: i64, ex: i64, ey: i64, ew: i64, eh: i64, label: *u8, pass: *i64) -> i64 { 98 let m: i64 = geom_match(tree, i, ex, ey, ew, eh) 99 let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 100 g_w(" " as *u8); g_w(label); g_w(": " as *u8) 101 if m==1 { g_w("OK\n" as *u8); pass[0]=pass[0]+1 } 102 else { 103 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) 104 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) 105 } 106 return m 107} 108 109func main() -> i64 { 110 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0 111 g_w("=== GRID-TRACK GATE (px/fr track sizing + gaps, sovereign nx_cc->nxasm) ===\n" as *u8) 112 113 let html2: *u8 = "<div id=\"g\"><div id=\"a\">A</div><div id=\"b\">B</div></div>\x00" as *u8 114 let html3: *u8 = "<div id=\"g\"><div id=\"a\">A</div><div id=\"b\">B</div><div id=\"c\">C</div></div>\x00" as *u8 115 let html4: *u8 = "<div id=\"g\"><div id=\"a\">A</div><div id=\"b\">B</div><div id=\"c\">C</div><div id=\"d\">D</div></div>\x00" as *u8 116 117 // T1 MIXED: 200px fixed + 2 fr (vw=800 -> 200, then leftover 600/2 = 300 each) 118 let t1: *LayoutTree = run_layout(html3, "#g{display:grid;grid-template-columns:200px 1fr 1fr}\x00" as *u8, 800) 119 g_w("T1 200px 1fr 1fr (fixed + fr leftover)\n" as *u8) 120 // ONE LINE BOX = NX_INLINE_LINE_H from nx_layout_block, never a literal. TRACK WIDTHS AND GAPS 121 // BELOW STAY LITERAL -- they are real CSS px from the fixture, not font-derived. 122 let LH: i64 = NX_INLINE_LINE_H 123 chk(t1, 2, 0, 0, 200, LH, "#a fixed x=0 w=200\x00" as *u8, pass) 124 chk(t1, 4, 200, 0, 300, LH, "#b fr x=200 w=300\x00" as *u8, pass) 125 chk(t1, 6, 500, 0, 300, LH, "#c fr x=500 w=300\x00" as *u8, pass) 126 127 // T2 WEIGHTED fr: 1fr 2fr (vw=900 -> 300 / 600) 128 let t2: *LayoutTree = run_layout(html2, "#g{display:grid;grid-template-columns:1fr 2fr}\x00" as *u8, 900) 129 g_w("T2 1fr 2fr (weighted share)\n" as *u8) 130 chk(t2, 2, 0, 0, 300, LH, "#a 1fr x=0 w=300\x00" as *u8, pass) 131 chk(t2, 4, 300, 0, 600, LH, "#b 2fr x=300 w=600\x00" as *u8, pass) 132 133 // T3 COLUMN-GAP: 1fr 1fr column-gap:20px (vw=800 -> 390 each, col1 x=410) 134 let t3: *LayoutTree = run_layout(html2, "#g{display:grid;grid-template-columns:1fr 1fr;column-gap:20px}\x00" as *u8, 800) 135 g_w("T3 column-gap:20px\n" as *u8) 136 chk(t3, 2, 0, 0, 390, LH, "#a x=0 w=390\x00" as *u8, pass) 137 chk(t3, 4, 410, 0, 390, LH, "#b x=410 (gap 20) w=390\x00" as *u8, pass) 138 139 // T4 GAP shorthand + WRAP: 1fr 1fr gap:10px, 4 kids (vw=800 -> 395 each; col1 x=405; row1 y=20) 140 let t4: *LayoutTree = run_layout(html4, "#g{display:grid;grid-template-columns:1fr 1fr;gap:10px}\x00" as *u8, 800) 141 g_w("T4 gap:10px + wrap (col-gap AND row-gap)\n" as *u8) 142 // row1 y = ONE LINE + the declared 10px row-gap. The gap stays literal (CSS, not font metrics); 143 // only the line term derives -- so this reads as the arithmetic it actually is, not a lump 20. 144 chk(t4, 6, 0, LH + 10, 395, LH, "#c row1 x=0 y=line+gap\x00" as *u8, pass) 145 chk(t4, 8, 405, LH + 10, 395, LH, "#d row1 x=405 y=line+gap\x00" as *u8, pass) 146 147 // T5 repeat(N, px): repeat(2, 150px) (vw=800 -> two fixed 150px cols) 148 let t5: *LayoutTree = run_layout(html2, "#g{display:grid;grid-template-columns:repeat(2, 150px)}\x00" as *u8, 800) 149 g_w("T5 repeat(2, 150px) (repeated fixed track)\n" as *u8) 150 chk(t5, 2, 0, 0, 150, LH, "#a x=0 w=150\x00" as *u8, pass) 151 chk(t5, 4, 150, 0, 150, LH, "#b x=150 w=150\x00" as *u8, pass) 152 153 // LIAR-KILL: wrong width for T1 #b (real fr w=300, claim 200) -> honest checker MUST return 0 154 g_w("LIAR-KILL (wrong geometry must be rejected)\n" as *u8) 155 let lk: i64 = geom_match(t1, 4, 200, 0, 200, LH) 156 g_w(" rejects bad w=200 for fr col #b: " as *u8) 157 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) } 158 159 g_w("GRID-TRACK rows=12 pass=" as *u8); pn(pass[0]) 160 if pass[0]==12 { g_w(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 161 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1 162}