rpncalc-v4/tracer/main.js

105 lines
3.0 KiB
JavaScript

import {execRPN, step} from './shiny.mjs';
import {parseExprs} from './parse.mjs';
import {tokenize} from './token.mjs';
import {scope, customHandler} from './builtin.mjs';
//const scope = {};
//const customHandler = a => [a];
const inbox = document.getElementById("inbox")
const insbox = document.getElementById("insbox")
const outbox = document.getElementById("outbox")
const stepb = document.getElementById("step")
const play = document.getElementById("play")
const load = document.getElementById("load")
let state = null;
let input = null;
const highlight = (str, start, end, color) => {
return str.slice(0, start) + `<span style='background-color:${color}'>` + str.slice(start, end) + "</span>" + str.slice(end);
}
const loadState = () => {
input = inbox.value;
let toks = tokenize(input);
let ast = parseExprs(toks);
console.log(ast);
if (ast.parsed === null) {
insbox.innerHTML = "could not parse AST!"
} else if (ast.stream.length !== 0) {
insbox.innerHTML = highlight(input, ast.stream[0].startPos, ast.stream[0].endPos, "red");
insbox.innerHTML += "<br>unexpected token"
input = null;
state = null;
return;
}
insbox.innerHTML = input;
outbox.innerHTML = "";
state = {scopes:[scope], stacks:[[]], calls:[ast.parsed.arr]};
}
load.onclick = _ => {
loadState();
}
play.onclick = _ => {
if (state === null) {
loadState();
}
insbox.innerHTML = "";
while (state.calls[0].length > 0 || state.calls.length > 1) {
step(state, customHandler);
if (state.stacks.length > 4096) {
insbox.innerHTML = "max recursion depth exceeded"
return;
}
}
outbox.innerHTML = prettyprint(state.stacks[0]);
state = null;
input = null;
}
stepb.onclick = _ => {
if (state === null) {
return;
}
if (state.calls[0].length > 0 || state.calls.length > 1) {
let pos = step(state, customHandler);
if (!(pos.start === 0 && pos.end === 0)) {
insbox.innerHTML = highlight(input, pos.start, pos.end, "green");
}
if (state.stacks.length > 1) {
outbox.innerHTML = "... " + prettyprint(state.stacks[state.stacks.length-1]);
} else {
outbox.innerHTML = prettyprint(state.stacks[0]);
}
if (state.stacks.length > 4096) {
insbox.innerHTML = "max recursion depth exceeded"
return;
}
}
}
const show = (elem) => {
if (elem.type === "pair") {
return "{" + show(elem.val.fst) + ", " + show(elem.val.snd) + "}"
} else if (elem.type === "closure") {
return "(needs: " + elem.val.args.join(", ") + ")"
} else if (elem.type === "array") {
return "[" + prettyprint(elem.val) + "]"
} else {
return "(" + elem.val + ": " + elem.type + ")"
}
}
const prettyprint = (out) => {
let str = "";
for (let i = 0; i < out.length; i++) {
str += show(out[i]);
if (i < out.length - 1) {
str += " ";
}
}
return str;
}