Skip to content

Commit

Permalink
Run compiler and code in web worker
Browse files Browse the repository at this point in the history
  • Loading branch information
lpil committed Jan 19, 2024
1 parent 3edd3a3 commit de91b7c
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 61 deletions.
75 changes: 14 additions & 61 deletions static/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import CodeFlask from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";
import initGleamCompiler from "./compiler.js";
import stdlib from "./stdlib.js";

const output = document.querySelector("#output");
const initialCode = document.querySelector("#code").innerHTML;
Expand Down Expand Up @@ -38,63 +36,12 @@ const prismGrammar = {
/\b(?:0b[0-1]+|0o[0-7]+|[[:digit:]][[:digit:]_]*(\\.[[:digit:]]*)?|0x[[:xdigit:]]+)\b/,
};

// Monkey patch console.log to keep a copy of the output
let logged = "";
const log = console.log;
console.log = (...args) => {
log(...args);
logged += args.map((e) => `${e}`).join(" ") + "\n";
};

function resetLogCapture() {
logged = "";
}

async function compileEval(project, code) {
try {
project.writeModule("main", code);
project.compilePackage("javascript");
const js = project.readCompiledJavaScript("main");
const main = await loadProgram(js);
resetLogCapture();
if (main) main();
replaceOutput(logged, "log");
} catch (error) {
console.error(error);
replaceOutput(logged, "log");
appendOutput(error.toString(), "error");
}
for (const warning of project.takeWarnings()) {
appendOutput(warning, "warning");
}
}

async function loadProgram(js) {
const url = new URL(import.meta.url);
url.pathname = "";
url.hash = "";
url.search = "";
const href = url.toString();
const js1 = js.replaceAll(
/from\s+"\.\/(.+)"/g,
`from "${href}precompiled/$1"`,
);
const js2 = btoa(unescape(encodeURIComponent(js1)));
const module = await import("data:text/javascript;base64," + js2);
return module.main;
}

function clearOutput() {
while (output.firstChild) {
output.removeChild(output.firstChild);
}
}

function replaceOutput(content, className) {
clearOutput();
appendOutput(content, className);
}

function appendOutput(content, className) {
if (!content) return;
const element = document.createElement("pre");
Expand All @@ -109,12 +56,6 @@ const editor = new CodeFlask("#editor-target", {
editor.addLanguage("gleam", prismGrammar);
editor.updateCode(initialCode);

const compiler = await initGleamCompiler();
const project = compiler.newProject();
for (const [name, code] of Object.entries(stdlib)) {
project.writeModule(name, code);
}

function debounce(fn, delay) {
let timer = null;
return (...args) => {
Expand All @@ -123,5 +64,17 @@ function debounce(fn, delay) {
};
}

editor.onUpdate(debounce((code) => compileEval(project, code), 200));
compileEval(project, initialCode);
const worker = new Worker("worker.js", { type: "module" });

worker.onmessage = (event) => {
const result = event.data;
clearOutput();
if (result.log) appendOutput(result.log, "log");
if (result.error) appendOutput(result.error, "error");
for (const warning of result.warnings) {
appendOutput(warning, "warning");
}
};

editor.onUpdate(debounce((code) => worker.postMessage(code), 200));
worker.postMessage(initialCode);
67 changes: 67 additions & 0 deletions static/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import initGleamCompiler from "./compiler.js";
import stdlib from "./stdlib.js";

const compiler = await initGleamCompiler();
const project = compiler.newProject();

for (const [name, code] of Object.entries(stdlib)) {
project.writeModule(name, code);
}

// Monkey patch console.log to keep a copy of the output
let logged = "";
const log = console.log;
console.log = (...args) => {
log(...args);
logged += args.map((e) => `${e}`).join(" ") + "\n";
};

function resetLogCapture() {
logged = "";
}

async function loadProgram(js) {
const url = new URL(import.meta.url);
url.pathname = "";
url.hash = "";
url.search = "";
const href = url.toString();
const js1 = js.replaceAll(
/from\s+"\.\/(.+)"/g,
`from "${href}precompiled/$1"`,
);
const js2 = btoa(unescape(encodeURIComponent(js1)));
const module = await import("data:text/javascript;base64," + js2);
return module.main;
}

async function compileEval(code) {
const result = {
log: null,
error: null,
warnings: [],
};

try {
project.writeModule("main", code);
project.compilePackage("javascript");
const js = project.readCompiledJavaScript("main");
const main = await loadProgram(js);
resetLogCapture();
if (main) main();
} catch (error) {
console.error(error);
result.error = error.toString();
}
for (const warning of project.takeWarnings()) {
result.warnings.push(warning);
}
result.log = logged;

return result;
}

self.onmessage = async (event) => {
const result = compileEval(event.data);
postMessage(await result);
};

0 comments on commit de91b7c

Please sign in to comment.