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}