const STATUS = document.getElementById("status-line"); const DOC_CHAINS = {}; function chain_document_submit(kind, editor, on_success) { let pending = null; let next = null; function do_submit() { const document = editor.doc.getValue(); if (window.localStorage) { window.localStorage.setItem(kind, document); } if (pending) { console.log("Old still pending, parking it..."); next = document; } else { pending = document; worker.postMessage({kind, data: document}); console.log("Document submitted"); } } function on_result(message) { pending = null; if (next) { pending = next; next = null; worker.postMessage({kind, data: document}); console.log("Posted another document"); } if (message.status === "ok" && on_success) { on_success(message); } } DOC_CHAINS[kind] = on_result; let change_timer_id = null; editor.doc.on("change", () => { clearTimeout(change_timer_id); change_timer_id = setTimeout(() => { change_timer_id = null; do_submit(); }, 100); }); if (window.localStorage) { const value = window.localStorage.getItem(kind); if (value) { editor.doc.setValue(value); } } return do_submit; } const worker = new Worker('worker.js'); worker.onmessage = (e) => { const message = e.data; const chain = DOC_CHAINS[message.kind]; if (chain) { chain(message); } STATUS.innerText = message.message; }; let grammar_editor = null; let input_editor = null; function render_parse_results(message) { function render_tree_node(parent, node) { const tree_div = document.createElement("div"); tree_div.classList.add("parsed-node"); const node_label = document.createElement("a"); node_label.innerText = node.name; node_label.setAttribute("href", "#"); node_label.onclick = () => { const doc = input_editor.doc; doc.setSelection( doc.posFromIndex(node.start), doc.posFromIndex(node.end), {scroll: true}, ); }; if (node.start == node.end) { node_label.classList.add("parsed-error-node"); } tree_div.appendChild(node_label); if (node.kind === "tree") { tree_div.classList.add("parsed-tree"); for (const child of node.children) { render_tree_node(tree_div, child); } } else { tree_div.classList.add("parsed-token"); } parent.appendChild(tree_div); } const root = document.getElementById("output-root"); root.innerHTML = ""; render_tree_node(root, message.tree); } function setup_editors() { grammar_editor = CodeMirror.fromTextArea( document.getElementById("grammar"), { lineNumbers: true, mode: "python", }, ); input_editor = CodeMirror.fromTextArea( document.getElementById("input"), { lineNumbers: true, }, ); const submit_input = chain_document_submit( "input", input_editor, render_parse_results); chain_document_submit( "grammar", grammar_editor, submit_input); } setup_editors();