code wiki / _hdl_build / nx_negmargin_gate.nx

nx_negmargin_gate.nx source

↩ module page · 152 lines · 8830 B

1// nx_negmargin_gate.nx -- VERDICT gate for NEGATIVE MARGINS (box overlap). A negative margin-top pulls a 2// block UP over its predecessor; a negative margin-left shifts it LEFT (possibly to a negative x). Asserts 3// exact box x/y vs a no-margin CONTROL (proves the shift is real, not a no-op) + a positive-margin 4// regression check + LIAR-KILL (the shifted box is NOT where the control box sits). Exercises the full 5// chain: tokenizer ('-'+digit -> negative NUMBER) -> nx_css_number_parse (sign) -> _layout_margin_px 6// (unset sentinel, no clamp). 100% sovereign nx_cc->nxasm. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_css_tokenize.nx" 9import "nx_css_parse.nx" 10import "nx_css_apply.nx" 11import "nx_css_color_decode.nx" 12import "nx_css_dimension_to_px.nx" 13import "nx_css_selector_match.nx" 14import "nx_html_tokenizer.nx" 15import "nx_dom_query.nx" 16import "nx_layout_box.nx" 17import "nx_layout_default_display.nx" 18import "nx_layout_from_dom.nx" 19import "nx_layout_block.nx" 20import "nx_render_html.nx" 21 22func 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 } 23func 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 } 24 25func run_layout(html: *u8, css: *u8, vw: i64, tree_out: **LayoutTree, boxel_out: **CssElement, buf_out: **u8) -> i64 { 26 var hlen: i64 = 0 27 while html[hlen]!=(0 as u8) { hlen=hlen+1 } 28 var clen: i64 = 0 29 while css[clen]!=(0 as u8) { clen=clen+1 } 30 let total: i64 = hlen + clen 31 let buf: *u8 = sys_mmap(total + 16) 32 var i: i64 = 0 33 while i < hlen { buf[i]=html[i]; i=i+1 } 34 var j: i64 = 0 35 while j < clen { buf[hlen+j]=css[j]; j=j+1 } 36 let boxes: *LayoutBox = (sys_mmap(NX_LAYOUT_BOX_BYTES*1024+16)) as *LayoutBox 37 let tree: *LayoutTree = (sys_mmap(64)) as *LayoutTree 38 nx_layout_tree_init(tree, boxes, 1024) 39 let stk: *LayoutFromDomStack = (sys_mmap(NX_LAYOUT_FROM_DOM_STACK_BYTES+8)) as *LayoutFromDomStack 40 let sidx: *i64 = (sys_mmap(8*64)) as *i64 41 nx_layout_from_dom_stack_init(stk, sidx, 64) 42 nx_layout_from_dom(buf, hlen, tree, stk) 43 let ext: *CssElement = (sys_mmap(NX_CSS_ELEMENT_BYTES*1024 as nx_size)) as *CssElement 44 let n_ext: i64 = rh_extract(buf, hlen, ext, 1024) 45 let boxel: *CssElement = (sys_mmap((NX_CSS_ELEMENT_BYTES*(tree.count+1)) as nx_size)) as *CssElement 46 var k: i64 = 0 47 i = 0 48 while i < tree.count { 49 let bb: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox 50 let e: *CssElement = ((boxel as i64)+i*NX_CSS_ELEMENT_BYTES) as *CssElement 51 e.src = buf 52 var mapped: i64 = 0 53 if rh_is_elem(bb.kind)==1 { if bb.parent_idx != (0-1) { if k < n_ext { 54 let s: *CssElement = ((ext as i64)+k*NX_CSS_ELEMENT_BYTES) as *CssElement 55 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 56 k=k+1; mapped=1 57 } } } 58 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 } 59 i=i+1 60 } 61 let cur: *CssCursor = (sys_mmap(NX_CSS_CURSOR_BYTES) as nx_size) as *CssCursor 62 nx_css_cursor_init(cur, buf, total); cur.pos = hlen 63 let tok: *CssToken = (sys_mmap(NX_CSS_TOKEN_BYTES) as nx_size) as *CssToken 64 let rules: *CssRule = (sys_mmap(NX_CSS_RULE_BYTES*512 as nx_size)) as *CssRule 65 let decls: *CssDeclaration = (sys_mmap(NX_CSS_DECLARATION_BYTES*512 as nx_size)) as *CssDeclaration 66 let st: *CssParseState = (sys_mmap(128) as nx_size) as *CssParseState 67 nx_css_parse_state_init(st, cur, tok, rules, 512, decls, 512) 68 nx_css_parse(st) 69 let computed: *CssComputedDecl = (sys_mmap(NX_CSS_COMPUTED_DECL_BYTES*4096 as nx_size)) as *CssComputedDecl 70 let cb: *i64 = (sys_mmap(8)) as *i64 71 rh_cascade(buf, rules, st.rule_count, decls, st.decl_count, boxel, tree.count, tree, computed, 4096, cb) 72 let ncomp: i64 = cb[0] 73 let pbuf: *u8 = sys_mmap(256) 74 let ltable: *LayoutPropTable = (sys_mmap(NX_LAYOUT_PROP_TABLE_BYTES)) as *LayoutPropTable 75 nx_layout_prop_table_init(ltable, pbuf) 76 let resolve: *CssResolveCtx = (sys_mmap(NX_CSS_RESOLVE_CTX_BYTES)) as *CssResolveCtx 77 resolve.root_font_size_px = 16; resolve.parent_font_size_px = 16; resolve.parent_dimension_px = vw 78 let lctx: *LayoutCtx = (sys_mmap(NX_LAYOUT_CTX_BYTES)) as *LayoutCtx 79 nx_layout_ctx_init(lctx, tree, computed, ncomp, buf, vw, resolve) 80 nx_layout_block_layout(lctx, ltable, 0) 81 tree_out[0] = tree; boxel_out[0] = boxel; buf_out[0] = buf 82 return 0 83} 84func find_class(tree: *LayoutTree, boxel: *CssElement, buf: *u8, cls: *u8) -> i64 { 85 var cl: i64 = 0 86 while cls[cl]!=(0 as u8) { cl=cl+1 } 87 var i: i64 = 0 88 while i < tree.count { 89 let e: *CssElement = ((boxel as i64)+i*NX_CSS_ELEMENT_BYTES) as *CssElement 90 if e.class_len >= cl { 91 var off: i64 = e.class_off; var pe: i64 = e.class_off+e.class_len; var hit: i64 = 0 92 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 } } 93 if hit==1 { return i } 94 } 95 i = i + 1 96 } 97 return 0 - 1 98} 99func box_y(tree: *LayoutTree, i: i64) -> i64 { let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox; return b.y } 100func box_x(tree: *LayoutTree, i: i64) -> i64 { let b: *LayoutBox = ((tree.boxes as i64)+i*NX_LAYOUT_BOX_BYTES) as *LayoutBox; return b.x } 101func chk(got: i64, want: i64, label: *u8, pass: *i64) -> i64 { 102 g_w(" " as *u8); g_w(label); g_w(": " as *u8) 103 if got==want { g_w("OK (" as *u8); pn(got); g_w(")\n" as *u8); pass[0]=pass[0]+1 } 104 else { g_w("FAIL got " 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("=== NEGATIVE-MARGIN GATE (box overlap, sovereign) ===\n" as *u8) 111 let stack: *u8 = "<div id=\"p\"><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: b stacks directly below a (a h=30) -> b.y = 30 117 run_layout(stack, "#p{}.a{height:30px}.b{height:30px}\x00" as *u8, 800, tp, bp, up) 118 let bi_c: i64 = find_class(tp[0], bp[0], up[0], "b\x00" as *u8) 119 let cy: i64 = box_y(tp[0], bi_c) 120 g_w("control (no margin): b stacks at y=30\n" as *u8) 121 chk(cy, 30, "b y=30 (control)\x00" as *u8, pass) 122 123 // NEGATIVE margin-top: b pulled UP 20px -> b.y = 10 124 run_layout(stack, "#p{}.a{height:30px}.b{height:30px;margin-top:-20px}\x00" as *u8, 800, tp, bp, up) 125 let bi_n: i64 = find_class(tp[0], bp[0], up[0], "b\x00" as *u8) 126 let ny: i64 = box_y(tp[0], bi_n) 127 g_w("margin-top:-20px: b pulled up to y=10\n" as *u8) 128 chk(ny, 10, "b y=10 (neg margin-top)\x00" as *u8, pass) 129 130 // NEGATIVE margin-left: c shifted LEFT to x=-15 131 run_layout("<div id=\"p\"><div class=\"c\"></div></div>\x00" as *u8, "#p{}.c{margin-left:-15px;width:10px;height:10px}\x00" as *u8, 800, tp, bp, up) 132 let ci: i64 = find_class(tp[0], bp[0], up[0], "c\x00" as *u8) 133 g_w("margin-left:-15px: c shifted to x=-15\n" as *u8) 134 chk(box_x(tp[0], ci), 0-15, "c x=-15 (neg margin-left)\x00" as *u8, pass) 135 136 // REGRESSION: positive margin-left still places at x=40 137 run_layout("<div id=\"p\"><div class=\"d\"></div></div>\x00" as *u8, "#p{}.d{margin-left:40px;width:10px;height:10px}\x00" as *u8, 800, tp, bp, up) 138 let di: i64 = find_class(tp[0], bp[0], up[0], "d\x00" as *u8) 139 g_w("margin-left:40px: d at x=40 (positive still works)\n" as *u8) 140 chk(box_x(tp[0], di), 40, "d x=40 (pos margin-left)\x00" as *u8, pass) 141 142 // LIAR-KILL: the neg-margin b (y=10) is NOT where the control b sits (y=30) 143 // LIAR-KILL uses the CAPTURED y values (not a re-read of tp[0], which now holds a later scenario's tree): 144 // the neg-margin b (10) must NOT sit where the control b (30) does -> proves the margin really shifted it. 145 g_w("LIAR-KILL (neg-margin shifted b OFF the control position)\n" as *u8) 146 g_w(" neg b.y(" as *u8); pn(ny); g_w(") != control b.y(" as *u8); pn(cy); g_w("): " as *u8) 147 if ny != cy { g_w("OK\n" as *u8); pass[0]=pass[0]+1 } else { g_w("FAIL (no shift)\n" as *u8) } 148 149 g_w("NEGMARGIN rows=5 pass=" as *u8); pn(pass[0]) 150 if pass[0]==5 { g_w(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 151 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1 152}