MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

prevent curried monad leaks for T_TAILCALL

+69 -11
+3 -1
src/ant.c
··· 7874 7874 js->tail_ctx = false; 7875 7875 if (res != (jsval_t)T_TAILCALL) res = resolveprop(js, res); 7876 7876 } else { 7877 + js->tail_ctx = false; 7877 7878 res = js_eval(js, &fn[pf->body_start], pf->body_len); 7878 7879 if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 7879 7880 } ··· 11713 11714 return res; 11714 11715 } 11715 11716 uint8_t stmt_tok = js->tok; 11716 - jsval_t res = resolveprop(js, js_stmt(js)); 11717 + jsval_t res = js_stmt(js); 11718 + if (res != (jsval_t)T_TAILCALL) res = resolveprop(js, res); 11717 11719 bool is_block_stmt = ( 11718 11720 stmt_tok == TOK_FUNC || stmt_tok == TOK_CLASS || 11719 11721 stmt_tok == TOK_IF || stmt_tok == TOK_WHILE ||
+55
tests/repro_bouncer_collectdecl.js
··· 1 + const bouncer = (f, ini) => { 2 + let obj = ini; 3 + while (obj.tag) obj = f(obj); 4 + return obj.h0; 5 + }; 6 + 7 + const Nil = { tag: 0 }; 8 + const Cons = (h, t) => ({ tag: 1, h1: h, h2: t }); 9 + 10 + function mkList(n) { 11 + let xs = Nil; 12 + for (let i = n; i > 0; i--) xs = Cons(i, xs); 13 + return xs; 14 + } 15 + 16 + const collectBad = xs => bouncer(collectBadREC, { tag: 1, h0: xs }); 17 + const collectBadREC = arg => { 18 + if (arg.h0.tag === 1) { 19 + return { tag: 0, h0: Cons(arg.h0.h1, collectBad(arg.h0.h2)) }; 20 + } 21 + return { tag: 0, h0: Nil }; 22 + }; 23 + 24 + const collectGood = xs => reverse(bouncer(collectGoodREC, { tag: 1, h0: xs, h1: Nil })); 25 + const collectGoodREC = arg => { 26 + if (arg.h0.tag === 1) return { tag: 1, h0: arg.h0.h2, h1: Cons(arg.h0.h1, arg.h1) }; 27 + return { tag: 0, h0: arg.h1 }; 28 + }; 29 + 30 + function reverse(xs) { 31 + let out = Nil; 32 + while (xs.tag === 1) { 33 + out = Cons(xs.h1, out); 34 + xs = xs.h2; 35 + } 36 + return out; 37 + } 38 + 39 + const n = Number(process.argv[2] || 5000); 40 + const xs = mkList(n); 41 + 42 + let badOverflow = false; 43 + try { 44 + collectBad(xs); 45 + } catch (_) { 46 + badOverflow = true; 47 + } 48 + 49 + if (!badOverflow) { 50 + console.log('FAIL: expected collectBad to overflow'); 51 + process.exit(1); 52 + } 53 + 54 + collectGood(xs); 55 + console.log('PASS');
+1 -1
tests/test_tco_curried.js
··· 106 106 const pure = v => MkM(tc => eta => ({ tag: 1, h2: { h2: tc, h3: v } })); 107 107 108 108 let chain = pure(0); 109 - for (let i = 0; i < 200; i++) { 109 + for (let i = 0; i < 800; i++) { 110 110 chain = bind(chain, v => pure(v + 1)); 111 111 } 112 112 const monadResult = chain.h1({})(0);
+10 -9
tests/test_tco_monad.js
··· 1 1 // Monad-style bind chain (simplified newt pattern) 2 - const MkM = (h1) => ({ tag: 0, h1: h1 }); 2 + const MkM = h1 => ({ tag: 0, h1: h1 }); 3 3 4 - const bind = (m, f) => MkM((tc) => (eta) => { 5 - const sc = m.h1(tc)(eta); 6 - if (sc.tag === 1) return f(sc.h2.h3).h1(sc.h2.h2)(eta); 7 - return sc; 8 - }); 4 + const bind = (m, f) => 5 + MkM(tc => eta => { 6 + const sc = m.h1(tc)(eta); 7 + if (sc.tag === 1) return f(sc.h2.h3).h1(sc.h2.h2)(eta); 8 + return sc; 9 + }); 9 10 10 - const pure = (v) => MkM((tc) => (eta) => ({ tag: 1, h2: { h2: tc, h3: v } })); 11 + const pure = v => MkM(tc => eta => ({ tag: 1, h2: { h2: tc, h3: v } })); 11 12 12 13 let chain = pure(0); 13 - for (let i = 0; i < 100; i++) { 14 - chain = bind(chain, (v) => pure(v + 1)); 14 + for (let i = 0; i < 800; i++) { 15 + chain = bind(chain, v => pure(v + 1)); 15 16 } 16 17 const result = chain.h1({})(0); 17 18 console.log('monad chain result:', result.h2.h3); // 100