code wiki / _hdl_build / nx_js_update_gate.nx

nx_js_update_gate.nx source

↩ module page · 68 lines · 4899 B

1// nx_js_update_gate.nx -- SINGLE-EVALUATION of the reference in ++/-- update expressions on BOTH tiers. 2// JS spec: `a[expr]++` / `obj.prop++` evaluate the target reference (base sub-expr, and index sub-expr) 3// EXACTLY ONCE. The engine's compound-assign path (`a[k]+=e`) was already fixed to single-eval (BC_DUP2), 4// but the UPDATE path (c_update / tree ND_UPDATE) re-evaluated base+key for the write-back -> a side-effecting 5// key/base runs TWICE (spec violation; e.g. `a[i++]++`, `f().x++`). CONFIRMED via nx_js_upd_min (c=2 for 6// `a[k()]++` pre-fix). This gate pins single-eval + correct prefix(NEW)/postfix(OLD) result + write, on the 7// tree tier (js_run_source) AND the VM/JIT tier (compile_run). Two direct-call helpers (no branch-on-static: 8// that combo miscompiled -> SIGSEGV). expect_exit: 0 license_tier: ORIGINAL 9import "nx_js_vm.nx" 10func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 11func nn(v: i64) -> i64 { if v==0 { sys_write(1,"0" as *u8,1); return 0 } var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } let t: *u8=sys_mmap(24); var k: i64=0; while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } let o: *u8=sys_mmap(24); var q: i64=k-1; var x: i64=0; while q>=0 { o[x]=t[q]; x=x+1; q=q-1 } sys_write(1,o,x); return 0 } 12static g_want: i64 13func ct(label: *u8, src: *u8) -> i64 { // TREE tier 14 let rt: *i64 = sys_mmap(16) as *i64 15 let r: i64 = js_run_source(src, bsl(src), rt) 16 w(" " as *u8); w(label); w(": rc=" as *u8); nn(r); w(" got=" as *u8); nn(rt[1]); w(" want=" as *u8); nn(g_want) 17 if r == 0 { if rt[1] == g_want { w(" ok\n" as *u8); return 1 } } 18 w(" FAIL\n" as *u8) 19 return 0 20} 21func cv(label: *u8, src: *u8) -> i64 { // VM/JIT tier 22 let rt: *i64 = sys_mmap(16) as *i64 23 let r: i64 = compile_run(src, rt) 24 w(" " as *u8); w(label); w(": rc=" as *u8); nn(r); w(" got=" as *u8); nn(rt[1]); w(" want=" as *u8); nn(g_want) 25 if r == 0 { if rt[1] == g_want { w(" ok\n" as *u8); return 1 } } 26 w(" FAIL\n" as *u8) 27 return 0 28} 29func tree_suite() -> i64 { 30 var p: i64 = 0 31 g_want=1; p=p+ct("idx-key-once " as *u8, "var c=0; function k(){c=c+1;return 0;} var a=[10]; a[k()]++; c" as *u8) 32 g_want=11; p=p+ct("idx-write " as *u8, "var c=0; function k(){c=c+1;return 0;} var a=[10]; a[k()]++; a[0]" as *u8) 33 g_want=10; p=p+ct("idx-post-result" as *u8, "var a=[10]; var r=a[0]++; r" as *u8) 34 g_want=11; p=p+ct("idx-pre-result " as *u8, "var a=[10]; var r=++a[0]; r" as *u8) 35 g_want=10; p=p+ct("idx-post-dec " as *u8, "var a=[10]; a[0]--; a[0]==9 ? 10 : 0" as *u8) 36 g_want=1; p=p+ct("idx-base-once " as *u8, "var c=0; var a=[10]; function g(){c=c+1;return a;} g()[0]++; c" as *u8) 37 g_want=1; p=p+ct("mem-base-once " as *u8, "var c=0; var box={v:10}; function g(){c=c+1;return box;} g().v++; c" as *u8) 38 g_want=11; p=p+ct("mem-write " as *u8, "var c=0; var box={v:10}; function g(){c=c+1;return box;} g().v++; box.v" as *u8) 39 g_want=1; p=p+ct("cmpd-key-once " as *u8, "var c=0; function k(){c=c+1;return 0;} var a=[10]; a[k()]+=5; c" as *u8) 40 g_want=6; p=p+ct("ident-pre " as *u8, "var x=5; ++x" as *u8) 41 return p 42} 43func vm_suite() -> i64 { 44 var p: i64 = 0 45 g_want=1; p=p+cv("idx-key-once " as *u8, "var c=0; function k(){c=c+1;return 0;} var a=[10]; a[k()]++; c" as *u8) 46 g_want=11; p=p+cv("idx-write " as *u8, "var c=0; function k(){c=c+1;return 0;} var a=[10]; a[k()]++; a[0]" as *u8) 47 g_want=10; p=p+cv("idx-post-result" as *u8, "var a=[10]; var r=a[0]++; r" as *u8) 48 g_want=11; p=p+cv("idx-pre-result " as *u8, "var a=[10]; var r=++a[0]; r" as *u8) 49 g_want=10; p=p+cv("idx-post-dec " as *u8, "var a=[10]; a[0]--; a[0]==9 ? 10 : 0" as *u8) 50 g_want=1; p=p+cv("idx-base-once " as *u8, "var c=0; var a=[10]; function g(){c=c+1;return a;} g()[0]++; c" as *u8) 51 g_want=1; p=p+cv("mem-base-once " as *u8, "var c=0; var box={v:10}; function g(){c=c+1;return box;} g().v++; c" as *u8) 52 g_want=11; p=p+cv("mem-write " as *u8, "var c=0; var box={v:10}; function g(){c=c+1;return box;} g().v++; box.v" as *u8) 53 g_want=1; p=p+cv("cmpd-key-once " as *u8, "var c=0; function k(){c=c+1;return 0;} var a=[10]; a[k()]+=5; c" as *u8) 54 g_want=6; p=p+cv("ident-pre " as *u8, "var x=5; ++x" as *u8) 55 return p 56} 57func main(argc: i64, argv: *i64) -> i64 { 58 w("=== nx_js_update_gate: single-eval of ++/-- reference (both tiers) ===\n" as *u8) 59 var pass: i64 = 0 60 w("--- tree tier (js_run_source) ---\n" as *u8) 61 pass = pass + tree_suite() 62 w("--- VM/JIT tier (compile_run) ---\n" as *u8) 63 pass = pass + vm_suite() 64 w(" --- " as *u8); nn(pass); w("/20 ---\n" as *u8) 65 if pass == 20 { w("=== GREEN: ++/-- evaluate the reference exactly once, correct prefix/postfix, both tiers ===\n" as *u8); return 0 } 66 w("=== RED ===\n" as *u8) 67 return 1 68}