var websocket = undefined; function generateRandomToken() { const array = new Uint8Array(16); window.crypto.getRandomValues(array); return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join(''); } function connect() { websocket = (function() { const host = window.location.host; const params = new URLSearchParams(window.location.search); let token = generateRandomToken(); if (params.has("token")) { token = params.get("token"); } const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; const ws = new WebSocket(protocol + "//" + host + "/repl/" + token); ws.binaryType = "arraybuffer"; return ws; })(); websocket.onopen = function(e) { document.getElementById("command").classList.remove("disconnected"); document.getElementById("command").classList.add("connected"); document.getElementById("connect").src = "images/connected.png"; document.getElementById("connect").removeEventListener("click", connect); }; websocket.onclose = function(e) { document.getElementById("command").classList.remove("connected"); document.getElementById("command").classList.add("disconnected"); document.getElementById("connect").src = "images/connect.png"; document.getElementById("connect").addEventListener("click", connect); }; websocket.onmessage = function(e) { const reader = new FileReader(); reader.addEventListener('loadend', readMessageAndAppend(reader)); if(e.data instanceof ArrayBuffer) { reader.readAsText(new Blob([e.data])); } else { reader.readAsText(e.data); } }; } var commandHistory = []; function appendOutput(text) { const root = document.getElementById("minilang"); const sub = document.createElement("div"); sub.classList.add("output"); sub.appendChild(text); if(root.firstChild) { root.insertBefore(sub, root.firstChild); } else { root.appendChild(sub); } }; function prettyAST(term) { if(term.tag === "Sym") { return term.contents; } else if(term.tag === "Abs") { return "(lam (" + term.contents[0].join(" ") + ") " + prettyAST(term.contents[1]) + ")"; } else if(term.tag === "App") { const pref = "(" + prettyAST(term.contents[0]) + " " + prettyAST(term.contents[1]); if(term.contents[2]) { return pref + " " + term.contents[2].map(prettyAST).join(" ") + ")"; } else { return pref + ")"; } } return JSON.stringify(term); } function prettyType(type) { if(type.tag === "TyVar") { return type.contents; } else if(type.tag === ":->") { return "(" + prettyType(type.contents[0]) + " -> " + prettyType(type.contents[1]) + ")"; } return JSON.stringify(type); } function formatResult(text) { const result = JSON.parse(text); if (result.tag === "Evaluated") { return prettyAST(result.contents[0]) + ' : ' + prettyType(result.contents[2]); } else if (result.tag === "Msg" ) { return result.contents; } return text; } function readMessageAndAppend(reader) { return () => { appendOutput(document.createTextNode(formatResult(reader.result))); }; }; function makeCommand(val) { const words = val.split(/ +/); if(words[0] === ":env") { return {tag:"Com",contents:{tag:"DumpEnv"}}; } else if(words[0] === ":clear") { return {tag:"Com",contents:{tag:"ClearEnv"}}; } else if(words[0] === ":help") { return {tag:"Com",contents:{tag:"Help"}}; } else if(words[0] === ":lang") { return {tag:"Com",contents:{tag:"Set", contents:{tag: "SelectLanguage", contents:words[1]}}}; } else { return {tag:"In",contents:val}; } }; function sendCommand(e) { const input = document.getElementById("command"); if (e.keyCode == 13) { const command = makeCommand(input.value); appendOutput(document.createTextNode("> "+ input.value)); commandHistory.push(input.value); websocket.send(JSON.stringify(command)); input.value = ""; return false; } else if(e.keyCode == 38) { input.value = commandHistory.pop() || ""; return false; } return true; }; function loadText(e) { const text = document.getElementById("program").value; const command = {tag:"Com", contents:{ tag:"Load", contents:{ tag:"Data", contents:text}}}; websocket.send(JSON.stringify(command)); return false; }; function toggleHelp(e) { const help = document.getElementById("help"); if(help.style.display === "block") { help.style.display = "none"; } else { help.style.display = "block"; } } document.getElementById("command").addEventListener("keyup", sendCommand); document.getElementById("connect").addEventListener("click", connect); document.getElementById("send").addEventListener("click", loadText); document.getElementById("helptip").addEventListener("click", toggleHelp); document.getElementById("help").addEventListener("click", toggleHelp); connect();