156 lines
3.5 KiB
JavaScript
156 lines
3.5 KiB
JavaScript
const STATUS = document.getElementById("status-line");
|
|
const ERRORS = document.getElementById("error-root");
|
|
const TREE = document.getElementById("tree-root");
|
|
|
|
function show_tree() {
|
|
ERRORS.classList.add("hidden");
|
|
TREE.classList.remove("hidden");
|
|
}
|
|
|
|
function show_errors() {
|
|
ERRORS.classList.remove("hidden");
|
|
TREE.classList.add("hidden");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
if (message.status === "error") {
|
|
render_errors(message.errors);
|
|
}
|
|
}
|
|
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_errors(errors) {
|
|
ERRORS.innerText = errors.join("\n")
|
|
}
|
|
|
|
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("tree-root");
|
|
root.innerHTML = "";
|
|
render_tree_node(root, message.tree);
|
|
render_errors(message.errors);
|
|
}
|
|
|
|
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();
|