modularize playground (prep for persistent/modular file handling)

This commit is contained in:
2024-12-07 16:58:10 -08:00
parent 421f5ea208
commit ba70845c09
11 changed files with 673 additions and 193 deletions

View File

@@ -1,165 +1,39 @@
class Buffer extends ArrayBuffer {
static alloc(n: number) {
return new Buffer(n);
}
indexOf(n: number) {
let view = new Uint8Array(this);
return view.indexOf(n);
}
import { shim } from "./emul";
import { archive, preload } from "./preload";
import { CompileReq, CompileRes } from "./types";
static concat(bufs: Buffer[]) {
let size = bufs.reduce((a, b) => (a += b.byteLength), 0);
let rval = new Buffer(size);
let view = new Uint8Array(rval);
let off = 0;
for (let buf of bufs) {
view.set(new Uint8Array(buf), off);
off += buf.byteLength;
}
return rval;
}
toString() {
return new TextDecoder().decode(this);
}
}
let files: Record<string, string> = {};
interface Handle {
name: string;
mode: string;
pos: number;
buf: Buffer;
}
let fds: Handle[] = [];
let shim: any = {
os: {
platform() {
return "linux";
},
},
fs: {
openSync(name: string, mode: string) {
console.log("open", name, arguments);
let te = new TextEncoder();
let fd = fds.findIndex((x) => !x);
if (fd < 0) fd = fds.length;
let buf;
let pos = 0;
if (mode == "w") {
buf = new Buffer(0);
} else {
if (!files[name]) throw new Error(`${name} not found`);
buf = te.encode(files[name]);
}
fds[fd] = { buf, pos, mode, name };
// we'll mutate the pointer as stuff is read
return fd;
},
writeSync(fd: number, line: string) {
if (typeof line !== "string") throw new Error("not implemented");
let handle = fds[fd];
if (!handle) throw new Error(`bad fd ${fd}`)
let buf2 = new TextEncoder().encode(line);
handle.buf = Buffer.concat([handle.buf, buf2])
},
chmodSync(fn: string, mode: number) { },
readSync(fd: number, buf: Buffer, start: number, len: number) {
let hand = fds[fd];
let avail = hand.buf.byteLength - hand.pos;
let rd = Math.min(avail, len);
let src = new Uint8Array(hand.buf);
let dest = new Uint8Array(buf);
for (let i = 0; i < rd; i++) dest[start + i] = src[hand.pos++];
return rd;
},
closeSync(fd: number) {
let handle = fds[fd];
if (handle.mode == "w") {
files[handle.name] = new TextDecoder().decode(handle.buf);
}
delete fds[fd];
},
},
};
// Spy on Idris' calls to see what we need to fill in
shim.fs = new Proxy(shim.fs, {
get(target, prop, receiver) {
if (prop in target) {
return (target as any)[prop];
}
throw new Error(`implement fs.${String(prop)}`)
},
});
const process: Process = {
platform: "linux",
argv: ["", ""],
stdout: {
// We'll want to replace this one
write: console.log,
},
exit(v: number) {
console.log("exit", v);
},
// stdin: { fd: 0 },
};
const require = (x: string) => shim[x];
// Maybe the shim goes here and we append newt...
let stdout = ''
// We'll want to collect and put info in the monaco
process.stdout.write = (s) => {
stdout += s
};
// hack for now
const preload = [
"Prelude.newt",
"Web.newt",
"aoc2023/day1/eg.txt",
"aoc2023/day1/eg2.txt",
]
const handleMessage = async function (e) {
console.log('message for you sir', e.data)
for (let fn of preload) {
if (!files[fn]) {
console.log('preload', fn)
let res = await fetch(fn)
let text = await res.text()
files[fn] = text
}
}
let {src} = e.data
let module = 'Main'
let m = src.match(/module (\w+)/)
if (m) module = m[1]
let fn = `${module}.newt`
process.argv = ["", "", fn, "-o", "out.js", "--top"];
console.log("args", process.argv);
files[fn] = src;
files['out.js'] = 'No JS output';
stdout = ''
const start = +new Date()
const handleMessage = async function (ev: {data: CompileReq}) {
console.log("message", ev.data);
await preload;
shim.archive = archive;
let { src } = ev.data;
let module = "Main";
let m = src.match(/module (\w+)/);
if (m) module = m[1];
let fn = `${module}.newt`;
const outfile = "out.js";
shim.process.argv = ["", "", fn, "-o", outfile, "--top"];
console.log("Using args", shim.process.argv);
shim.files[fn] = new TextEncoder().encode(src);
shim.files[outfile] = new TextEncoder().encode("No JS output");
shim.stdout = "";
const start = +new Date();
try {
newtMain();
} catch (e) {
// make it clickable
console.error(e)
// make it visable
stdout += '\n' + String(e)
// make it clickable in console
console.error(e);
// make it visable on page
shim.stdout += "\n" + String(e);
}
let duration = +new Date() - start
console.log(`process ${fn} in ${duration} ms`)
let javascript = files['out.js']
let output = stdout
sendResponse({javascript, output, duration})
}
let sendResponse = postMessage
onmessage = handleMessage
let duration = +new Date() - start;
console.log(`shim.process ${fn} in ${duration} ms`);
let javascript = new TextDecoder().decode(shim.files[outfile]);
let output = shim.stdout;
sendResponse({ javascript, output, duration });
};
importScripts('newt.js')
// hooks for worker.html to override
let sendResponse : (_: CompileRes) => void = postMessage;
onmessage = handleMessage;
importScripts("newt.js");