diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2022-03-13 16:41:31 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-13 16:41:31 -0400 |
| commit | 748122a4238246965ab4fed70b9c36a04609d1a5 (patch) | |
| tree | 417cb22f9abe3e97110339f57aba0464a161bc6a /docs | |
| parent | f036d93326170963e69cba2f652811d6dcab81dd (diff) | |
| parent | e31ed99a5df67af7e80c8694c1d9ad5170c328f2 (diff) | |
Merge pull request #61 from andreypopp/master
Add repl preview
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/bqn.js | 67 |
1 files changed, 53 insertions, 14 deletions
diff --git a/docs/bqn.js b/docs/bqn.js index ea539d43..4bc4aead 100644 --- a/docs/bqn.js +++ b/docs/bqn.js @@ -46,6 +46,15 @@ let listkeys = x => { let getv= (a,i) => { let v=a[i]; if (v===null) throw Error("Runtime: Variable referenced before definition"); return v; } let get = x => x.e ? getv(x.e,x.p) : arr(x.map(c=>get(c)), x.sh); +let preview = false; +let inpreview = () => preview; + +let setc = (d, id, v) => { + if (preview && !id.e.inpreview) + throw {kind: 'previewError', message: 'side effects are not allowed'}; + return set(d, id, v); +} + let set = (d, id, v) => { let eq = (a,b) => a.length===b.length && a.every((e,i)=>e===b[i]); if (id.e) { @@ -78,6 +87,7 @@ let chkM = (v,m) => { if (m.m!==v) throw Error("Runtime: Only a "+v+"-modifier c let genjs = (B, p, L) => { // Bytecode -> Javascript compiler let rD = 0; let r = L?"let l=0;try{":""; + let set = L?"setc":"set" let fin = L?"}catch(er){let s=L.map(p=>p[l]);s.sh=[1,2];let m=[s,er.message];m.loc=1;m.src=e.vid.src;m.sh=[2];er.message=m;throw er;}":""; let szM = 1; let rV = n => { szM=Math.max(szM,n+1); return 'v'+n; }; @@ -108,10 +118,10 @@ let genjs = (B, p, L) => { // Bytecode -> Javascript compiler case 43: { let m=rG(); r+=rP("{match:1,v:"+m+"}"); break; } case 44: { r+=rP("{match:1}"); break; } case 47: { let i=rG(), v=rG(); r+="try{set(1,"+i+","+v+");}catch(e){break;}"; break; } - case 48: { let i=rG(), v=rG(); r+=rP("set(1,"+i+","+v +")"); break; } - case 49: { let i=rG(), v=rG(); r+=rP("set(0,"+i+","+v +")"); break; } - case 50: { let i=rG(),f=rG(),x=rG(); r+=rP("set(0,"+i+",call("+f+","+x+",get("+i+")))"); break; } - case 51: { let i=rG(),f=rG() ; r+=rP("set(0,"+i+",call("+f+ ",get("+i+")))"); break; } + case 48: { let i=rG(), v=rG(); r+=rP(set+"(1,"+i+","+v +")"); break; } + case 49: { let i=rG(), v=rG(); r+=rP(set+"(0,"+i+","+v +")"); break; } + case 50: { let i=rG(),f=rG(),x=rG(); r+=rP(set+"(0,"+i+",call("+f+","+x+",get("+i+")))"); break; } + case 51: { let i=rG(),f=rG() ; r+=rP(set+"(0,"+i+",call("+f+ ",get("+i+")))"); break; } case 66: { let m=rG(); r+=rP("{vid:e.vid,m:"+m+",a:"+num()+"}"); break; } case 64: { let v=rG(); r+=rP("readns("+v+",e.vid,"+num()+")"); break; } } @@ -135,20 +145,21 @@ let run = (B,O,F,S,L,T,src,env) => { // Bytecode, Objects, Blocks, Bodies, Locat return [genjs(B, pos, L), vid]; } + let ginpreview = e => L ? (e + ".inpreview=inpreview()") : ""; let c,vid,def; if (isnum(ind)) { [c,vid] = gen(ind); c="do {"+c+"} while (0);\nthrow Error('No matching case');\n"; if (useenv) { c = "const e=env;"+c; env.vid=vid; } - else if (imm) c = "const e=[...e2];e.vid=vid;e.p=oe;"+c; - else c = "const fn=(x, w)=>{const e=[...e2];e.vid=vid;e.p=oe;e[0]=fn;e[1]=x;e[2]=w;"+c+"};"+repdf[type]+"return fn;"; + else if (imm) c = "const e=[...e2];"+ginpreview('e')+";e.vid=vid;e.p=oe;"+c; + else c = "const fn=(x, w)=>{const e=[...e2];"+ginpreview('e')+";e.vid=vid;e.p=oe;e[0]=fn;e[1]=x;e[2]=w;"+c+"};"+repdf[type]+"return fn;"; def = useenv ? "env" : ("new Array("+vid.length+").fill(null)"); } else { if (imm !== +(ind.length<2)) throw "Internal error: malformed block info"; let cache=[]; // Avoid generating a shared case twice vid=[]; let g = j => { let [c,v] = cache[j] || (cache[j] = gen(j)); - c = "const e=[...e1];e.vid=vid["+vid.length+"];e.p=oe;e.length="+v.length+";e.fill(null,"+sp+");"+c; + c = "const e=[...e1];"+ginpreview('e')+";e.vid=vid["+vid.length+"];e.p=oe;e.length="+v.length+";e.fill(null,"+sp+");"+c; vid.push(v); return "do {"+c+"} while (0);\n" } @@ -157,11 +168,11 @@ let run = (B,O,F,S,L,T,src,env) => { // Bytecode, Objects, Blocks, Bodies, Locat let e = js.length?"No matching case":"Left argument "+(i?"not allowed":"required"); return js.map(g).concat(["throw Error('"+e+"');\n"]).join(""); }); - let fn = b => "(x, w)=>{const e1=[...e2];e1[0]=fn;e1[1]=x;e1[2]=w;\n"+b+"\n};"; + let fn = b => "(x, w)=>{const e1=[...e2];"+ginpreview('e1')+";e1[0]=fn;e1[1]=x;e1[2]=w;\n"+b+"\n};"; let combine = ([mon,dy]) => fn("if (w===undefined) {\n"+mon+"} else {\n"+dy+"}"); def = "new Array("+sp+").fill(null)"; - if (imm) c = "const e1=[...e2];"+cases[0]; + if (imm) c = "const e1=[...e2];"+ginpreview('e1')+";"+cases[0]; else { c = "const fn="+combine(cases)+repdf[type]; if (cases.length > 2) { @@ -172,12 +183,12 @@ let run = (B,O,F,S,L,T,src,env) => { // Bytecode, Objects, Blocks, Bodies, Locat } } - let de2 = "let e2="+def+";" + let de2 = "let e2="+def+";"+ginpreview('e2')+";" if (type===0) c = de2+c; if (type===1) c = "const mod=(f ) => {"+de2+" e2["+I+"]=mod;e2["+(I+1)+"]=f;" +c+"}; mod.m=1;return mod;"; if (type===2) c = "const mod=(f,g) => {"+de2+" e2["+I+"]=mod;e2["+(I+1)+"]=f;e2["+(I+2)+"]=g;"+c+"}; mod.m=2;return mod;"; - return Function("'use strict'; return (chkM,has,call,getv,get,set,llst,train2,train3,readns,O,L,env,vid) => D => oe => {"+c+"};")() - (chkM,has,call,getv,get,set,llst,train2,train3,readns,O,L,env,vid); + return Function("'use strict'; return (chkM,has,call,getv,get,set,setc,llst,train2,train3,readns,O,L,env,vid,inpreview) => D => oe => {"+c+"};")() + (chkM,has,call,getv,get,set,setc,llst,train2,train3,readns,O,L,env,vid,inpreview); }); D.forEach((d,i) => {D[i]=d(D)}); return D[0]([]); @@ -581,9 +592,20 @@ let addprimitives = (state, p) => { } let rerepl = (repl, cmp, state) => { let rd = repl>1 ? 0 : -1; + let vars0, names0, redef0; let vars = [], names = [], redef = []; + vars.inpreview = true; state.addrt = [names,redef]; - return (x,w) => { + let copyarr = (to,src) => { + to.length = src.length; + for (let i=0;i<to.length;i++) to[i] = src[i]; + } + let f = (x,w) => { + if (preview) { + vars0 = vars.slice(0); + names0 = names.slice(0); + redef0 = redef.slice(0); + } names.sh=redef.sh=[names.length]; let c = cmp(x,w); let pnames = c[5][2][0]; @@ -591,8 +613,25 @@ let rerepl = (repl, cmp, state) => { names.push(...newv.map(i=>pnames[i])); redef.push(...newv.map(i=>rd)); vars .push(...newv.map(i=>null)); - return run(...c, vars); + try { + return run(...c, vars); + } finally { + if (preview) { + copyarr(vars, vars0); + copyarr(names, names0); + copyarr(redef, redef0); + } + } } + f.preview = (x,w) => { + preview = true; + try { + return f(x,w); + } finally { + preview = false; + } + }; + return f; } let primitives = dynsys(state => { let gl=state.glyphs.flat(), rt=state.runtime; |
