code wiki / _hdl_build / nx_js_event_loop_gate.nx
nx_js_event_loop_gate.nx source
↩ module page · 71 lines · 5491 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_js_event_loop_gate.nx -- proves the R-JS-EVENTLOOP rung: the WHATWG event-loop model actually
4// EXECUTES queued callbacks in the correct ORDER (not just "setTimeout no longer ReferenceErrors").
5// Runs each script, DRAINS the loop (js_run_source_read), then reads the final value of a global and
6// asserts it -- so the assertion observes effects that land AFTER the last top-level statement.
7// The discriminating tests (T1 sync<micro<macro, T3 macro-enqueues-micro=AmB) FAIL on any non-WHATWG
8// order, so a pass is real proof, not a constant. license_tier: ORIGINAL
9import "nx_js_eval.nx"
10
11func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
12" as *u8); return ok }
13func gsl(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
14
15// run+drain, read global `rn`, assert it EQUALS the string `want`.
16func gr_str(label: *u8, src: *u8, rn: *u8, want: *u8) -> i64 {
17 let out: *i64 = sys_mmap(16) as *i64
18 let rc: i64 = js_run_source_read(src, gsl(src), rn, out)
19 gw(" "); gw(label); gw(": " as *u8)
20 if rc != 0 { gw("FAIL (eval rc=1)\n" as *u8); return 0 }
21 if out[0] != VAL_STR { gw("FAIL (not a string)\n" as *u8); return 0 }
22 let rec: *i64 = (out[1]) as *i64
23 let wl: i64 = gsl(want)
24 if ev_str_len(rec) != wl { gw("FAIL (len; got '" as *u8); sys_write(1, ev_str_bytes(rec), ev_str_len(rec)); gw("')\n" as *u8); return 0 }
25 let rb: *u8 = ev_str_bytes(rec)
26 var i: i64 = 0
27 while i < wl { if (rb[i] & 0xff) != (want[i] & 0xff) { gw("FAIL (got '" as *u8); sys_write(1, rb, wl); gw("' want '" as *u8); gw(want); gw("')\n" as *u8); return 0 } i = i + 1 }
28 gw("ok ('" as *u8); gw(want); gw("')\n" as *u8); return 1
29}
30// run+drain, read global `rn`, assert it EQUALS the number `want`.
31func gr_num(label: *u8, src: *u8, rn: *u8, want: i64) -> i64 {
32 let out: *i64 = sys_mmap(16) as *i64
33 let rc: i64 = js_run_source_read(src, gsl(src), rn, out)
34 gw(" "); gw(label); gw(": " as *u8)
35 if rc != 0 { gw("FAIL (eval rc=1)\n" as *u8); return 0 }
36 if out[0] != VAL_NUM { gw("FAIL (not a number)\n" as *u8); return 0 }
37 if out[1] != want { gw("FAIL (got "); gn(out[1]); gw(" want "); gn(want); gw(")\n" as *u8); return 0 }
38 gw("ok ("); gn(want); gw(")\n" as *u8); return 1
39}
40
41func main(argc: i64, argv: *i64) -> i64 {
42 gw("=== nx_js_event_loop_gate: WHATWG event-loop EXECUTION + ORDER ===\n" as *u8)
43 var pass: i64 = 0
44 var tot: i64 = 0
45
46 // T0 sync-only: no regression + proves js_run_source_read reads a global correctly.
47 tot = tot + 1; pass = pass + gr_num("T0 sync-only (no regression)" as *u8, "var y=5;y=y+1;" as *u8, "y" as *u8, 6)
48 // T1 THE ORDER LAW: synchronous first, then microtask, then macrotask -> 'SMT'. Any other model fails.
49 tot = tot + 1; pass = pass + gr_str("T1 sync<micro<macro = SMT" as *u8, "var log='';setTimeout(function(){log=log+'T';},0);queueMicrotask(function(){log=log+'M';});log=log+'S';" as *u8, "log" as *u8, "SMT" as *u8)
50 // T2 the setTimeout BODY actually executes (mutates a global), not merely enqueues.
51 tot = tot + 1; pass = pass + gr_num("T2 setTimeout body runs" as *u8, "var x=0;setTimeout(function(){x=42;},0);" as *u8, "x" as *u8, 42)
52 // T3 DISCRIMINATOR: macro A enqueues micro m; m must drain BEFORE macro B -> 'AmB' (not 'ABm').
53 tot = tot + 1; pass = pass + gr_str("T3 macro-enqueues-micro = AmB" as *u8, "var log='';setTimeout(function(){log=log+'A';queueMicrotask(function(){log=log+'m';});},0);setTimeout(function(){log=log+'B';},0);" as *u8, "log" as *u8, "AmB" as *u8)
54 // T4 a timer callback is a real CLOSURE (captures its factory's arg).
55 tot = tot + 1; pass = pass + gr_num("T4 timer closure captures" as *u8, "function mk(v){return function(){r=v;};}var r=0;setTimeout(mk(7),0);" as *u8, "r" as *u8, 7)
56 // T5 requestAnimationFrame body runs (macrotask family).
57 tot = tot + 1; pass = pass + gr_num("T5 rAF body runs" as *u8, "var z=0;requestAnimationFrame(function(){z=9;});" as *u8, "z" as *u8, 9)
58 // T6 nested microtasks drain to exhaustion -> '012'.
59 tot = tot + 1; pass = pass + gr_str("T6 nested microtasks drain" as *u8, "var log='';queueMicrotask(function(){log=log+'1';queueMicrotask(function(){log=log+'2';});});log=log+'0';" as *u8, "log" as *u8, "012" as *u8)
60 // T7 many timers all run (FIFO; sum is order-independent = proves all three bodies fire).
61 tot = tot + 1; pass = pass + gr_num("T7 three timers all fire" as *u8, "var s=0;setTimeout(function(){s=s+1;},0);setTimeout(function(){s=s+10;},0);setTimeout(function(){s=s+100;},0);" as *u8, "s" as *u8, 111)
62 // T8 LIAR-KILL: a WRONG expectation must FAIL (the harness can distinguish orders). We assert the
63 // engine does NOT produce 'STM' for the T1 script -> gr_str returns 0 (mismatch) -> counts as pass here.
64 tot = tot + 1
65 let neg: i64 = gr_str("T8 liar-kill (expect NOT 'STM')" as *u8, "var log='';setTimeout(function(){log=log+'T';},0);queueMicrotask(function(){log=log+'M';});log=log+'S';" as *u8, "log" as *u8, "STM" as *u8)
66 if neg == 0 { pass = pass + 1; gw(" (correctly did NOT match wrong order -> liar-kill holds)\n" as *u8) } else { gw(" !! liar-kill BROKE: harness matched a wrong order\n" as *u8) }
67
68 gw("=== "); gn(pass); gw("/"); gn(tot); gw(" "); if pass == tot { gw("GREEN ===\n" as *u8) } else { gw("RED ===\n" as *u8) }
69 if pass == tot { return 0 }
70 return 1
71}