code wiki / _hdl_build / nx_js_compile.nx
nx_js_compile.nx source
↩ module page · 213 lines · 15770 B
1// nx_js_compile.nx -- the bytecode-VM PARITY GATE (rungs 2..5c): every chk() runs the SAME source
2// through the TREE-WALKER (js_run_source) and the VM (compile_run in nx_js_vm.nx) and requires
3// identical rc AND deep-equal values; chk_read() = the async read-after-drain twin. The VM library
4// lives in nx_js_vm.nx so other organs (nx_js_sota_bench) reuse it without duplicating the engine.
5// license_tier: ORIGINAL
6import "nx_js_vm.nx"
7func main(argc: i64, argv: *i64) -> i64 {
8 bw("=== nx_js_compile: rung-4b bytecode VM (functions/closures/objects) vs tree-walker ===\n" as *u8)
9 let pp: *i64 = sys_mmap(8) as *i64
10 let tp: *i64 = sys_mmap(8) as *i64
11 // rungs 2+3+4a (regression: the original 19)
12 chk("1+2*3" as *u8, "T1 int precedence" as *u8, pp, tp)
13 chk("var s=0;var i=1;while(i<=6){s=s*i;i=i+1;}s" as *u8, "T2 loop s stays 0" as *u8, pp, tp)
14 chk("var n=6;var f=1;var i=1;while(i<=n){f=f*i;i=i+1;}f" as *u8, "T3 factorial(6)" as *u8, pp, tp)
15 chk("var x=7;if(x>5){x=1;}else{x=2;}x" as *u8, "T4 if/else" as *u8, pp, tp)
16 chk("'ab'+'cd'" as *u8, "T5 string concat" as *u8, pp, tp)
17 chk("var a='hel';var b='lo';a+b" as *u8, "T6 string var concat" as *u8, pp, tp)
18 chk("1+'x'" as *u8, "T7 mixed num+str" as *u8, pp, tp)
19 chk("'a'<'b'" as *u8, "T8 string compare" as *u8, pp, tp)
20 chk("2<3" as *u8, "T9 num compare" as *u8, pp, tp)
21 chk("var r='';var i=0;while(i<3){r=r+'x';i=i+1;}r" as *u8, "T10 build string in loop" as *u8, pp, tp)
22 chk("var a=1;var b=5;a&&b" as *u8, "T11 && takes b" as *u8, pp, tp)
23 chk("var a=0;var b=5;a&&b" as *u8, "T12 && short-circuit" as *u8, pp, tp)
24 chk("var a=0;var b=5;a||b" as *u8, "T13 || takes b" as *u8, pp, tp)
25 chk("var a=7;var b=5;a||b" as *u8, "T14 || short-circuit" as *u8, pp, tp)
26 chk("!0" as *u8, "T15 unary not" as *u8, pp, tp)
27 chk("var x=3;!(x>5)" as *u8, "T16 not-gt" as *u8, pp, tp)
28 chk("0-5+3" as *u8, "T17 arith neg" as *u8, pp, tp)
29 chk("var n=4;-n" as *u8, "T18 unary neg" as *u8, pp, tp)
30 chk("var i=0;var c=0;while(i<10){if(i>2){if(i<7){c=c+1;}}i=i+1;}c" as *u8, "T19 nested-if loop" as *u8, pp, tp)
31 // rung 4b: FUNCTIONS + CLOSURES
32 chk("function add(a,b){return a+b;}add(3,4)" as *u8, "T20 fn decl+call" as *u8, pp, tp)
33 chk("function fib(n){if(n<2){return n;}return fib(n-1)+fib(n-2);}fib(10)" as *u8, "T21 recursion fib(10)" as *u8, pp, tp)
34 chk("function mk(){var c=0;return function(){c=c+1;return c;};}var f=mk();f();f();f()" as *u8, "T22 closure counter" as *u8, pp, tp)
35 chk("function mkAdd(x){return function(y){return x+y;};}var a5=mkAdd(5);a5(7)" as *u8, "T23 closure adder" as *u8, pp, tp)
36 chk("function mk(){var c=0;return function(){c=c+1;return c;};}var f=mk();var g=mk();f();f();g()" as *u8, "T24 closures independent" as *u8, pp, tp)
37 chk("var r=go();function go(){return 9;}r" as *u8, "T25 hoisted call-before-decl" as *u8, pp, tp)
38 chk("var d=(x)=>x*2;d(21)" as *u8, "T26 arrow" as *u8, pp, tp)
39 chk("(function(){return 5;})()" as *u8, "T27 IIFE" as *u8, pp, tp)
40 chk("function f(a,b=10){return a+b;}f(5)" as *u8, "T28 param default" as *u8, pp, tp)
41 chk("function f(a,...r){return r.length+a;}f(1,2,3,4)" as *u8, "T29 rest param" as *u8, pp, tp)
42 chk("function outer(){var t=3;function inner(){return t+1;}return inner();}outer()" as *u8, "T30 nested fn lexical" as *u8, pp, tp)
43 // rung 4b: OBJECTS + ARRAYS + MEMBER/INDEX
44 chk("var o={a:1,b:2};o.a+o.b" as *u8, "T31 object literal+member" as *u8, pp, tp)
45 chk("var o={a:1};o.a=5;o.a" as *u8, "T32 member assign" as *u8, pp, tp)
46 chk("var o={};o.x=7;o.x" as *u8, "T33 member create" as *u8, pp, tp)
47 chk("var o={p:{q:3}};o.p.q" as *u8, "T34 nested member" as *u8, pp, tp)
48 chk("var a=[10,20,30];a[1]" as *u8, "T35 array literal+index" as *u8, pp, tp)
49 chk("var a=[1];a[3]=9;a.length" as *u8, "T36 index assign extends" as *u8, pp, tp)
50 chk("var o={v:6,f:function(){return this.v;}};o.f()" as *u8, "T37 method this" as *u8, pp, tp)
51 chk("var o={a:1};o['a']" as *u8, "T38 index string key" as *u8, pp, tp)
52 chk("var x=5;x+=3;x" as *u8, "T39 compound ident" as *u8, pp, tp)
53 chk("var o={n:2};o.n+=5;o.n" as *u8, "T40 compound member" as *u8, pp, tp)
54 chk("var a=[4];a[0]+=2;a[0]" as *u8, "T41 compound index" as *u8, pp, tp)
55 chk("var a=[{n:1},{n:2}];a[1].n" as *u8, "T42 array of objects" as *u8, pp, tp)
56 chk("var o={};var k='dy';o[k]='v';o.dy" as *u8, "T43 computed key" as *u8, pp, tp)
57 // rung 4b: CONTROL FLOW
58 chk("var s=0;for(var i=0;i<5;i=i+1){s=s+i;}s" as *u8, "T44 for loop" as *u8, pp, tp)
59 chk("var s=0;var i=0;while(i<10){i=i+1;if(i==3){continue;}if(i>6){break;}s=s+i;}s" as *u8, "T45 break+continue" as *u8, pp, tp)
60 chk("var n=0;do{n=n+1;}while(n<4);n" as *u8, "T46 do-while" as *u8, pp, tp)
61 chk("var x=5;x>3?'big':'small'" as *u8, "T47 ternary" as *u8, pp, tp)
62 chk("var a=null;a??7" as *u8, "T48 nullish null" as *u8, pp, tp)
63 chk("0??9" as *u8, "T49 nullish keeps 0" as *u8, pp, tp)
64 chk("var a=[1,2];var b=[0,...a,3];b.join('-')" as *u8, "T50 spread+join" as *u8, pp, tp)
65 chk("var s=0;var a=[1,2,3];for(var x of a){s=s+x;}s" as *u8, "T51 for-of" as *u8, pp, tp)
66 chk("var o={a:1,b:2};var r='';for(var k in o){r=r+k;}r" as *u8, "T52 for-in" as *u8, pp, tp)
67 chk("var x=2;var r=0;switch(x){case 1:r=10;break;case 2:r=20;case 3:r=r+1;break;default:r=99;}r" as *u8, "T53 switch fallthrough" as *u8, pp, tp)
68 chk("var x=9;var r=0;switch(x){case 1:r=10;break;default:r=99;}r" as *u8, "T54 switch default" as *u8, pp, tp)
69 // rung 4b: NATIVES through js_native_apply + new + misc
70 chk("Math.max(3,7,5)" as *u8, "T55 Math.max" as *u8, pp, tp)
71 chk("'abc'.toUpperCase()" as *u8, "T56 str method" as *u8, pp, tp)
72 chk("'hello'.slice(1,3)" as *u8, "T57 str slice" as *u8, pp, tp)
73 chk("var a=[3,1];a.push(9);a.length" as *u8, "T58 arr push" as *u8, pp, tp)
74 chk("[3,1,9].indexOf(9)" as *u8, "T59 arr indexOf" as *u8, pp, tp)
75 chk("JSON.parse('{\"m\":9}').m" as *u8, "T60 JSON.parse member" as *u8, pp, tp)
76 chk("function P(n){this.n=n;}var p=new P(4);p.n" as *u8, "T61 new user ctor" as *u8, pp, tp)
77 chk("function f(){}typeof f" as *u8, "T62 typeof function" as *u8, pp, tp)
78 chk("typeof zzznotdeclared" as *u8, "T63 typeof undeclared" as *u8, pp, tp)
79 chk("var [a,b]=[3,4];a+b" as *u8, "T64 array destructure" as *u8, pp, tp)
80 chk("var {a,b}={a:1,b:2};a+b" as *u8, "T65 object destructure" as *u8, pp, tp)
81 chk("var t=`hi`;t+'!'" as *u8, "T66 template no-interp" as *u8, pp, tp)
82 chk("var o=null;o?.x" as *u8, "T67 optional chain" as *u8, pp, tp)
83 chk("navigator.platform" as *u8, "T68 BOM prop" as *u8, pp, tp)
84 chk("var s='';var f=function(n){if(n>0){s=s+n;f(n-1);}};f(3);s" as *u8, "T69 fn-expr recursion via var" as *u8, pp, tp)
85 // rung 5a: ++/-- (ND_UPDATE) -- prefix/postfix on ident/member/index
86 chk("var i=5;i++;i" as *u8, "T75 i++ statement" as *u8, pp, tp)
87 chk("var i=5;var j=i++;j*10+i" as *u8, "T76 postfix returns OLD" as *u8, pp, tp)
88 chk("var i=5;var j=++i;j*10+i" as *u8, "T77 prefix returns NEW" as *u8, pp, tp)
89 chk("var s=0;for(var i=0;i<5;i++){s+=i;}s" as *u8, "T78 for with i++" as *u8, pp, tp)
90 chk("var o={n:1};o.n++;o.n" as *u8, "T79 member postfix" as *u8, pp, tp)
91 chk("var a=[7];a[0]--;a[0]" as *u8, "T80 index postfix dec" as *u8, pp, tp)
92 chk("var a=[3];var x=a[0]++;x*10+a[0]" as *u8, "T81 index postfix OLD" as *u8, pp, tp)
93 chk("var o={n:2};++o.n" as *u8, "T82 member prefix NEW" as *u8, pp, tp)
94 chk("var n=0;var i=10;while(i-->5){n++;}n*100+i" as *u8, "T83 i-- in condition" as *u8, pp, tp)
95 // rung 5b: try/catch/finally + throw
96 chk("var r=0;try{throw 5;r=1;}catch(e){r=e;}r" as *u8, "T84 throw value caught" as *u8, pp, tp)
97 chk("var r=9;try{var o={};o.nope();}catch(e){r=typeof e;}r" as *u8, "T85 runtime err binds undefined" as *u8, pp, tp)
98 chk("var r=0;try{r=1;}catch(e){r=2;}r" as *u8, "T86 no-throw skips catch" as *u8, pp, tp)
99 chk("var r='';try{r=r+'t';}finally{r=r+'f';}r" as *u8, "T87 finally normal path" as *u8, pp, tp)
100 chk("var r='';try{throw 'x';}catch(e){r=r+e;}finally{r=r+'f';}r" as *u8, "T88 finally after catch" as *u8, pp, tp)
101 chk("function f(){throw 7;}var r=0;try{f();}catch(e){r=e;}r" as *u8, "T89 throw across frames" as *u8, pp, tp)
102 chk("var g='';function f(){try{return 'A';}finally{g=g+'F';}}f()+g" as *u8, "T90 return runs finally" as *u8, pp, tp)
103 chk("var r='';try{try{throw 'i';}catch(e){r=r+'1'+e;throw 'o';}}catch(e2){r=r+'2'+e2;}r" as *u8, "T91 nested rethrow to outer" as *u8, pp, tp)
104 chk("var r='';var i=0;while(i<3){i++;try{if(i==2){break;}r=r+i;}finally{r=r+'f';}}r+i" as *u8, "T92 break runs finally" as *u8, pp, tp)
105 // rung 5c: VM RE-ENTRY -- callback natives invoke VM closures through vm_call_closure
106 chk("var s=0;[1,2,3].forEach(function(x){s=s+x;});s" as *u8, "T96 forEach VM closure" as *u8, pp, tp)
107 chk("[1,2,3].map(function(x){return x*2;}).join('-')" as *u8, "T97 map+join" as *u8, pp, tp)
108 chk("[1,2,3,4].filter(function(x){return x%2==0;}).join('')" as *u8, "T98 filter" as *u8, pp, tp)
109 chk("[1,2,3,4].reduce(function(a,b){return a+b;},0)" as *u8, "T99 reduce" as *u8, pp, tp)
110 chk("[1,2,3].some(function(x){return x>2;})" as *u8, "T100 some" as *u8, pp, tp)
111 chk("[1,2,3].every(function(x){return x>0;})" as *u8, "T101 every" as *u8, pp, tp)
112 chk("var t='';[3,4].forEach(function(x){t=t+x;});t" as *u8, "T102 callback mutates outer" as *u8, pp, tp)
113 chk("function run(a,f){return a.map(f).join('');}run([1,2],function(x){return x+1;})" as *u8, "T103 fn passed through frames" as *u8, pp, tp)
114 chk("var r=0;try{[1].forEach(function(x){throw 9;});}catch(e){r=e;}r" as *u8, "T104 throw crosses re-entry" as *u8, pp, tp)
115 // rung 5c ASYNC: event loop + promises running VM closures (read-after-drain parity)
116 chk_read("var r=0;setTimeout(function(){r=42;},0);r=1;" as *u8, "r" as *u8, "A1 setTimeout drains" as *u8, pp, tp)
117 chk_read("var g=0;Promise.resolve(5).then(function(v){g=v*2;});g=1;" as *u8, "g" as *u8, "A2 promise then" as *u8, pp, tp)
118 chk_read("var o='';queueMicrotask(function(){o=o+'m';});setTimeout(function(){o=o+'t';},0);o=o+'s';" as *u8, "o" as *u8, "A3 micro-before-macro order" as *u8, pp, tp)
119 chk_read("var f=0;fetch('data:,hi').then(function(rs){return rs.text();}).then(function(t2){f=t2;});f=1;" as *u8, "f" as *u8, "A4 fetch chain hydrates" as *u8, pp, tp)
120 // ERROR PARITY (rc=1 on both engines)
121 chk("var o={};o.nope()" as *u8, "T70 missing method errors" as *u8, pp, tp)
122 chk("5+zzzundeclared" as *u8, "T71 ReferenceError load" as *u8, pp, tp)
123 chk("zzzundeclared=5" as *u8, "T72 ReferenceError assign" as *u8, pp, tp)
124 chk("var x=1/0;x" as *u8, "T73 div0 = Infinity (JS f64)" as *u8, pp, tp)
125 chk("break;" as *u8, "T74 top-level break errors" as *u8, pp, tp)
126 chk("throw 3;" as *u8, "T93 uncaught throw errors" as *u8, pp, tp)
127 chk("try{throw 1;}finally{}" as *u8, "T94 finally-only rethrows" as *u8, pp, tp)
128 chk("7/2" as *u8, "T95 non-exact div = float 3.5" as *u8, pp, tp)
129 chk("0/0" as *u8, "T96b 0/0 = NaN" as *u8, pp, tp)
130 chk("var r=0;try{var o={};o.zz();}catch(e){r=42;}r" as *u8, "T95b try/catch on real error" as *u8, pp, tp)
131 // --- rung-4c: template ${} interpolation on the VM (was declined -> tree; now compiled, parity-gated) ---
132 chk("\x60hello\x60" as *u8, "TT1 template no-interp" as *u8, pp, tp)
133 chk("var x=5;\x60v=${x}\x60" as *u8, "TT2 template ${x}" as *u8, pp, tp)
134 chk("var a=1;var b=2;\x60${a}-${b}\x60" as *u8, "TT3 template two interps" as *u8, pp, tp)
135 chk("var a=3;var b=4;\x60${a+b}\x60" as *u8, "TT4 template expr a+b" as *u8, pp, tp)
136 chk("var o={k:9};\x60k=${o.k}\x60" as *u8, "TT5 template member" as *u8, pp, tp)
137 chk("var x='w';\x60${x}!\x60" as *u8, "TT6 template leading interp" as *u8, pp, tp)
138 chk("var h='cdn';var p='6khysx';\x60https://${h}/${p}/master.m3u8\x60" as *u8, "TT7 template URL build" as *u8, pp, tp)
139 chk("\x60${1+2}\x60" as *u8, "TT8 template number coercion" as *u8, pp, tp)
140 chk("var a=[1,2,3];\x60n=${a.length}\x60" as *u8, "TT9 template arr.length" as *u8, pp, tp)
141 chk("var f=function(z){return z*2;};'r'+f(4)" as *u8, "TT10 str+call control" as *u8, pp, tp)
142 // NOTE: `${f(x)}` (a USER-FN CALL in a template interp) is NOT gated here: the VM computes it CORRECTLY
143 // (proven: (`${f(4)}`).length == 1 -> "8"), but the TREE-WALKER oracle has a pre-existing cross-ctx bug
144 // (its closure body lives in the original parse ctx; a sub-parsed ${} eval reads it from the wrong ctx ->
145 // returns "undefined", length 9). So the VM is MORE correct than the tree here; gating it would fail on the
146 // tree's bug, not ours. Tree fix (closures capture their def-ctx) is a separate follow-on.
147 // --- ES classes: ctor + prototype methods (parser keeps methods -> ND_CLASS in both engines) ---
148 chk("class A{constructor(x){this.x=x;}}var a=new A(5);a.x" as *u8, "TC1 class ctor+field" as *u8, pp, tp)
149 chk("class A{constructor(x){this.x=x;}g(){return this.x*2;}}var a=new A(5);a.g()" as *u8, "TC2 class method" as *u8, pp, tp)
150 chk("class P{constructor(a,b){this.a=a;this.b=b;}sum(){return this.a+this.b;}}var p=new P(3,4);p.sum()" as *u8, "TC3 class 2-field method" as *u8, pp, tp)
151 chk("class C{constructor(){this.n=0;}inc(){this.n=this.n+1;return this.n;}}var c=new C();c.inc();c.inc();c.inc()" as *u8, "TC4 stateful method x3" as *u8, pp, tp)
152 chk("class A{constructor(x){this.x=x;}g(){return this.x;}}var a=new A(7);var b=new A(9);a.g()+b.g()" as *u8, "TC5 two instances share proto" as *u8, pp, tp)
153 chk("class A{constructor(x){this.x=x;}dbl(){return this.x*2;}inc(){return this.x+1;}}var a=new A(10);a.dbl()+a.inc()" as *u8, "TC6 two methods" as *u8, pp, tp)
154 bw(" --- correctness: ")
155 bn(pp[0])
156 bw("/")
157 bn(tp[0])
158 bw(" (VM == tree-walker: values AND rc) ---\n" as *u8)
159
160 // speed head-to-head 1: the hot int loop (rung-2/3 regression metric)
161 let lsrc: *u8 = "var s=0;var i=0;while(i<100000){s=s+i;i=i+1;}s" as *u8
162 let two: *i64 = sys_mmap(16) as *i64
163 let a0: i64 = sys_now_us()
164 js_run_source(lsrc, bsl(lsrc), two)
165 let a1: i64 = sys_now_us()
166 let vmo: *i64 = sys_mmap(16) as *i64
167 let b0: i64 = sys_now_us()
168 compile_run(lsrc, vmo)
169 let b1: i64 = sys_now_us()
170 let tw_us: i64 = a1 - a0
171 let vm_us: i64 = b1 - b0
172 var okloop: i64 = 0
173 if cells_eq(two, vmo) == 1 { if vm_us < tw_us { okloop = 1 } }
174 bw(" speed loop100k: tree=")
175 bn(tw_us)
176 bw("us vm=")
177 bn(vm_us)
178 bw("us")
179 if vm_us > 0 { bw(" SPEEDUP=" as *u8); bn(tw_us / vm_us); bw("x" as *u8) }
180 bw("\n" as *u8)
181 // speed head-to-head 2: CALL-heavy recursion (the rung-4b metric)
182 let fsrc: *u8 = "function fib(n){if(n<2){return n;}return fib(n-1)+fib(n-2);}fib(15)" as *u8
183 let tf: *i64 = sys_mmap(16) as *i64
184 let c0: i64 = sys_now_us()
185 js_run_source(fsrc, bsl(fsrc), tf)
186 let c1: i64 = sys_now_us()
187 let vf: *i64 = sys_mmap(16) as *i64
188 let d0: i64 = sys_now_us()
189 compile_run(fsrc, vf)
190 let d1: i64 = sys_now_us()
191 let tw2: i64 = c1 - c0
192 let vm2: i64 = d1 - d0
193 var okfib: i64 = 0
194 if cells_eq(tf, vf) == 1 { if vm2 < tw2 { okfib = 1 } }
195 bw(" speed fib(15) calls: tree=")
196 bn(tw2)
197 bw("us vm=")
198 bn(vm2)
199 bw("us")
200 if vm2 > 0 { bw(" SPEEDUP=" as *u8); bn(tw2 / vm2); bw("x" as *u8) }
201 bw("\n" as *u8)
202
203 if pp[0] == tp[0] { if okloop == 1 { if okfib == 1 {
204 bw("=== GREEN: rung-4b VM CORRECT (")
205 bn(pp[0])
206 bw("/")
207 bn(tp[0])
208 bw(") + FASTER on loops AND calls ===\n" as *u8)
209 return 0
210 } } }
211 bw("=== RED ===\n" as *u8)
212 return 1
213}