code wiki / _hdl_build / nx_flexgrow_gate.nx
nx_flexgrow_gate.nx source
↩ module page · 164 lines · 9816 B
1// nx_flexgrow_gate.nx -- VERDICT gate for flexbox flex-grow (main-axis grow distribution). Auto-basis
2// flex items with flex-grow share the leftover main-axis space PROPORTIONALLY to their grow factor.
3// Cases: (1) no-grow CONTROL = current equal-share unchanged; (2) grow 1:2; (3) fixed sidebar + a
4// growing main (the canonical layout); (4) the `flex:N` shorthand; (5) LIAR-KILL: grow 1:2 is NOT an
5// equal 450/450 split. Asserts exact box WIDTH. 100% sovereign nx_cc->nxasm. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_css_tokenize.nx"
8import "nx_css_parse.nx"
9import "nx_css_apply.nx"
10import "nx_css_color_decode.nx"
11import "nx_css_dimension_to_px.nx"
12import "nx_css_selector_match.nx"
13import "nx_html_tokenizer.nx"
14import "nx_dom_query.nx"
15import "nx_layout_box.nx"
16import "nx_layout_default_display.nx"
17import "nx_layout_from_dom.nx"
18import "nx_layout_block.nx"
19import "nx_render_html.nx"
20
21func 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 }
22func 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 }
23
24func run_layout(html: *u8, css: *u8, vw: i64, tree_out: **LayoutTree, boxel_out: **CssElement, buf_out: **u8) -> i64 {
25 var hlen: i64 = 0
26 while html[hlen]!=(0 as u8) { hlen=hlen+1 }
27 var clen: i64 = 0
28 while css[clen]!=(0 as u8) { clen=clen+1 }
29 let total: i64 = hlen + clen
30 let buf: *u8 = sys_mmap(total + 16)
31 var i: i64 = 0
32 while i < hlen { buf[i]=html[i]; i=i+1 }
33 var j: i64 = 0
34 while j < clen { buf[hlen+j]=css[j]; j=j+1 }
35 let boxes: *LayoutBox = (sys_mmap(NX_LAYOUT_BOX_BYTES*1024+16)) as *LayoutBox
36 let tree: *LayoutTree = (sys_mmap(64)) as *LayoutTree
37 nx_layout_tree_init(tree, boxes, 1024)
38 let stk: *LayoutFromDomStack = (sys_mmap(NX_LAYOUT_FROM_DOM_STACK_BYTES+8)) as *LayoutFromDomStack
39 let sidx: *i64 = (sys_mmap(8*64)) as *i64
40 nx_layout_from_dom_stack_init(stk, sidx, 64)
41 nx_layout_from_dom(buf, hlen, tree, stk)
42 let ext: *CssElement = (sys_mmap(NX_CSS_ELEMENT_BYTES*1024 as nx_size)) as *CssElement
43 let n_ext: i64 = rh_extract(buf, hlen, ext, 1024)
44 let boxel: *CssElement = (sys_mmap((NX_CSS_ELEMENT_BYTES*(tree.count+1)) as nx_size)) as *CssElement
45 var k: i64 = 0
46 i = 0
47 while i < tree.count {
48 let bb: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox
49 let e: *CssElement = ((boxel as i64)+i*NX_CSS_ELEMENT_BYTES) as *CssElement
50 e.src = buf
51 var mapped: i64 = 0
52 if rh_is_elem(bb.kind)==1 { if bb.parent_idx != (0-1) { if k < n_ext {
53 let s: *CssElement = ((ext as i64)+k*NX_CSS_ELEMENT_BYTES) as *CssElement
54 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
55 k=k+1; mapped=1
56 } } }
57 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 }
58 i=i+1
59 }
60 let cur: *CssCursor = (sys_mmap(NX_CSS_CURSOR_BYTES) as nx_size) as *CssCursor
61 nx_css_cursor_init(cur, buf, total); cur.pos = hlen
62 let tok: *CssToken = (sys_mmap(NX_CSS_TOKEN_BYTES) as nx_size) as *CssToken
63 let rules: *CssRule = (sys_mmap(NX_CSS_RULE_BYTES*512 as nx_size)) as *CssRule
64 let decls: *CssDeclaration = (sys_mmap(NX_CSS_DECLARATION_BYTES*512 as nx_size)) as *CssDeclaration
65 let st: *CssParseState = (sys_mmap(128) as nx_size) as *CssParseState
66 nx_css_parse_state_init(st, cur, tok, rules, 512, decls, 512)
67 nx_css_parse(st)
68 let computed: *CssComputedDecl = (sys_mmap(NX_CSS_COMPUTED_DECL_BYTES*4096 as nx_size)) as *CssComputedDecl
69 let cb: *i64 = (sys_mmap(8)) as *i64
70 rh_cascade(buf, rules, st.rule_count, decls, st.decl_count, boxel, tree.count, tree, computed, 4096, cb)
71 let ncomp: i64 = cb[0]
72 let pbuf: *u8 = sys_mmap(256)
73 let ltable: *LayoutPropTable = (sys_mmap(NX_LAYOUT_PROP_TABLE_BYTES)) as *LayoutPropTable
74 nx_layout_prop_table_init(ltable, pbuf)
75 let resolve: *CssResolveCtx = (sys_mmap(NX_CSS_RESOLVE_CTX_BYTES)) as *CssResolveCtx
76 resolve.root_font_size_px = 16; resolve.parent_font_size_px = 16; resolve.parent_dimension_px = vw
77 let lctx: *LayoutCtx = (sys_mmap(NX_LAYOUT_CTX_BYTES)) as *LayoutCtx
78 nx_layout_ctx_init(lctx, tree, computed, ncomp, buf, vw, resolve)
79 nx_layout_block_layout(lctx, ltable, 0)
80 tree_out[0] = tree; boxel_out[0] = boxel; buf_out[0] = buf
81 return 0
82}
83func find_class(tree: *LayoutTree, boxel: *CssElement, buf: *u8, cls: *u8) -> i64 {
84 var cl: i64 = 0
85 while cls[cl]!=(0 as u8) { cl=cl+1 }
86 var i: i64 = 0
87 while i < tree.count {
88 let e: *CssElement = ((boxel as i64)+i*NX_CSS_ELEMENT_BYTES) as *CssElement
89 if e.class_len >= cl {
90 var off: i64 = e.class_off; var pe: i64 = e.class_off+e.class_len; var hit: i64 = 0
91 while off + cl <= pe { var j: i64=0; var ok: i64=1; while j<cl { if (buf[off+j]&0xff)!=(cls[j]&0xff){ok=0;j=cl} else {j=j+1} } if ok==1 { hit=1; off=pe } else { off=off+1 } }
92 if hit==1 { return i }
93 }
94 i = i + 1
95 }
96 return 0 - 1
97}
98func box_w(tree: *LayoutTree, i: i64) -> i64 { let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox; return b.w }
99func chkw(tree: *LayoutTree, boxel: *CssElement, buf: *u8, cls: *u8, want: i64, label: *u8, pass: *i64) -> i64 {
100 let bi: i64 = find_class(tree, boxel, buf, cls)
101 let got: i64 = box_w(tree, bi)
102 g_w(" " as *u8); g_w(label); g_w(": " as *u8)
103 if got==want { g_w("OK (w=" as *u8); pn(got); g_w(")\n" as *u8); pass[0]=pass[0]+1 }
104 else { g_w("FAIL got w=" as *u8); pn(got); g_w(" want " as *u8); pn(want); g_w("\n" as *u8) }
105 return 0
106}
107
108func main() -> i64 {
109 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0
110 g_w("=== FLEX-GROW GATE (flex main-axis grow distribution, sovereign) ===\n" as *u8)
111 let html: *u8 = "<div id=\"c\"><div class=\"a\"></div><div class=\"b\"></div></div>\x00" as *u8
112 let tp: **LayoutTree = sys_mmap(8) as **LayoutTree
113 let bp: **CssElement = sys_mmap(8) as **CssElement
114 let up: **u8 = sys_mmap(8) as **u8
115
116 // CONTROL (no flex-grow): two auto items split 800 EQUALLY = 400/400 (existing path unchanged)
117 run_layout(html, "#c{display:flex}\x00" as *u8, 800, tp, bp, up)
118 g_w("no-grow control (800 -> 400/400 equal share)\n" as *u8)
119 chkw(tp[0], bp[0], up[0], "a\x00" as *u8, 400, "a w=400\x00" as *u8, pass)
120 chkw(tp[0], bp[0], up[0], "b\x00" as *u8, 400, "b w=400\x00" as *u8, pass)
121
122 // grow 1:2 over 900 -> 300/600 (proportional, NOT equal)
123 run_layout(html, "#c{display:flex}.a{flex-grow:1}.b{flex-grow:2}\x00" as *u8, 900, tp, bp, up)
124 g_w("flex-grow 1:2 (900 -> 300/600)\n" as *u8)
125 chkw(tp[0], bp[0], up[0], "a\x00" as *u8, 300, "a w=300\x00" as *u8, pass)
126 chkw(tp[0], bp[0], up[0], "b\x00" as *u8, 600, "b w=600\x00" as *u8, pass)
127
128 // fixed sidebar (200px) + growing main: leftover 600 all to the grower (canonical app layout)
129 run_layout(html, "#c{display:flex}.a{width:200px}.b{flex-grow:1}\x00" as *u8, 800, tp, bp, up)
130 g_w("fixed 200 + grow:1 (800 -> 200/600)\n" as *u8)
131 chkw(tp[0], bp[0], up[0], "a\x00" as *u8, 200, "a w=200\x00" as *u8, pass)
132 chkw(tp[0], bp[0], up[0], "b\x00" as *u8, 600, "b w=600\x00" as *u8, pass)
133
134 // `flex:N` shorthand 1:3 over 800 -> 200/600 (first integer token = grow factor)
135 run_layout(html, "#c{display:flex}.a{flex:1}.b{flex:3}\x00" as *u8, 800, tp, bp, up)
136 g_w("flex:1 / flex:3 (800 -> 200/600)\n" as *u8)
137 chkw(tp[0], bp[0], up[0], "a\x00" as *u8, 200, "a w=200\x00" as *u8, pass)
138 chkw(tp[0], bp[0], up[0], "b\x00" as *u8, 600, "b w=600\x00" as *u8, pass)
139
140 // EXPLICIT-BASIS grow: .a has width:100px AND flex-grow:1; .b width:100px (no grow). leftover =
141 // 800-(100+100)=600 -> grow item a = 100+600 = 700, b stays 100. (Grows from its width basis, not 0.)
142 run_layout(html, "#c{display:flex}.a{width:100px;flex-grow:1}.b{width:100px}\x00" as *u8, 800, tp, bp, up)
143 g_w("explicit-basis grow .a{w100,grow1}/.b{w100} (800 -> 700/100)\n" as *u8)
144 chkw(tp[0], bp[0], up[0], "a\x00" as *u8, 700, "a w=700\x00" as *u8, pass)
145 chkw(tp[0], bp[0], up[0], "b\x00" as *u8, 100, "b w=100\x00" as *u8, pass)
146
147 // FRACTIONAL grow with Σgrow<1: .a{width:100px;flex-grow:0.5}/.b{width:100px} in 300 -> free=100,
148 // Σgrow=0.5<1 so only 0.5*100=50 is distributed -> a=100+50=150, b=100 (50px stays UNUSED, not filled).
149 run_layout(html, "#c{display:flex}.a{width:100px;flex-grow:0.5}.b{width:100px}\x00" as *u8, 300, tp, bp, up)
150 g_w("fractional grow 0.5, sum<1 (300 -> 150/100, 50 unused)\n" as *u8)
151 chkw(tp[0], bp[0], up[0], "a\x00" as *u8, 150, "a w=150 (0.5*free)\x00" as *u8, pass)
152 chkw(tp[0], bp[0], up[0], "b\x00" as *u8, 100, "b w=100\x00" as *u8, pass)
153
154 // LIAR-KILL: grow 1:2 is NOT an equal 450/450 split (proves distribution is proportional, not equal)
155 run_layout(html, "#c{display:flex}.a{flex-grow:1}.b{flex-grow:2}\x00" as *u8, 900, tp, bp, up)
156 let bi: i64 = find_class(tp[0], bp[0], up[0], "a\x00" as *u8)
157 g_w("LIAR-KILL (grow 1:2 != equal 450 split)\n" as *u8)
158 g_w(" a w != 450: " as *u8)
159 if box_w(tp[0], bi) != 450 { g_w("OK (w=" as *u8); pn(box_w(tp[0], bi)); g_w(")\n" as *u8); pass[0]=pass[0]+1 } else { g_w("FAIL (equal split, grow ignored)\n" as *u8) }
160
161 g_w("FLEXGROW rows=13 pass=" as *u8); pn(pass[0])
162 if pass[0]==13 { g_w(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
163 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1
164}