window.apfl_playground = (() => { let instances = new Map(); function playground_write(handle, error, s) { let inst = instances.get(handle); if (inst) { inst.write(error, s); } } window.playground_write = playground_write; let repl_new_for_playground = undefined; let repl_run = undefined; let repl_destroy = undefined; function Playground() { let h = repl_new_for_playground(); if (!h) { throw new Error("Could not init playground"); } this.echoSource = true; this._h = h; this._onOutput = null; this._onError = null; this._lastResult = Playground.REPL_OK; instances.set(h, this); } Playground.REPL_OK = 0; Playground.REPL_MORE_INPUT = 1; Playground.REPL_ERR = 2; Playground.REPL_FATAL = 3; Playground.prototype.destroy = function () { repl_destroy(this._h); instances.delete(this._h); }; Playground.prototype.onOutput = function (f) { this._onOutput = f; }; Playground.prototype.onError = function (f) { this._onError = f; }; Playground.prototype.write = function (error, s) { let writer = error ? this._onError : this._onOutput; if (writer) { writer(s); } } Playground.prototype.getPrompt = function () { return this._lastResult === Playground.REPL_MORE_INPUT ? "..." : ">"; }; Playground.prototype.runCode = function (source) { source += ""; if (this.echoSource) { this.write(false, `${this.getPrompt()} ${source}`); } return (this._lastResult = repl_run(this._h, source)); }; Playground.prototype.interactive = function (parent) { const elem = (name, inner) => { let out = document.createElement(name); if (inner) { inner(out); } return out; }; let output; let form; let prompt; let input; parent.appendChild(elem("DIV", outer => { outer.classList = "apfl_playground"; outer.appendChild(output = elem("PRE", output => { output.classList = "apfl_playground_output"; })) outer.appendChild(form = elem("FORM", form => { form.appendChild(prompt = elem("SPAN", prompt => { prompt.className = "apfl_playground_prompt"; prompt.innerText = this.getPrompt(); })); form.appendChild(input = elem("INPUT", input => { input.type = "text"; input.className = "apfl_playground_input"; input.placeholder = "code ..."; })); })) })); form.onsubmit = (e) => { e.preventDefault(); let code = input.value; input.value = ""; if (!code) { return; } this.runCode(code + "\n"); prompt.innerText = this.getPrompt(); }; const write = (error, s) => { var span = elem("SPAN"); if (error) { span.classList.add("error"); } var lines = s.split("\n"); var scroll = false; for (var i = 0 ; i < lines.length; i++) { if (i > 0) { span.appendChild(elem("BR")); scroll = true; } var line = lines[i]; if (line != "") { span.appendChild(document.createTextNode(lines[i])); } } output.append(span); if (scroll) { output.scrollTop = output.scrollHeight - output.clientHeight; } }; this.onOutput(s => write(false, s)); this.onError(s => write(true, s)); }; let ok = false let onModLoaded = []; return async function () { if (ok) { return Playground; } let p = new Promise(resolve => { onModLoaded.push(resolve); }); WasmApflPlayground().then(instance => { repl_new_for_playground = instance.cwrap("repl_new_for_playground", "number", []); repl_run = instance.cwrap("repl_run", "number", ["number", "string"]); repl_destroy = instance.cwrap("repl_destroy", "void", ["number"]); ok = true; onModLoaded.forEach(l => l(Playground)); }); return await p; }; })();