summaryrefslogtreecommitdiffstats
path: root/site/main.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'site/main.mjs')
-rw-r--r--site/main.mjs172
1 files changed, 13 insertions, 159 deletions
diff --git a/site/main.mjs b/site/main.mjs
index ffbda00..d99b3a3 100644
--- a/site/main.mjs
+++ b/site/main.mjs
@@ -1,3 +1,5 @@
+import Inspector from './inspector.mjs';
+
// simulation speed
let TICKS_PER_SECOND = 15;
let MS_PER_TICK = 1_000 / TICKS_PER_SECOND;
@@ -6,93 +8,9 @@ let MS_PER_TICK = 1_000 / TICKS_PER_SECOND;
const CANVAS_SELECTOR = '#arena canvas';
const TICK_BUTTON_SELECTOR = '#tick';
const TICK_RATE_SELECTOR = '#tick-rate-select';
-const BENCH_BUTTON_SELECTOR = '#bench';
const RUN_BUTTON_SELECTOR = '#run';
const FPS_SELECTOR = '#fps';
-// one per bot
-const SRC_SELECT_SELECTOR = '#src-select';
-const COMPILE_BUTTON_SELECTOR = '#compile';
-const WORDLIST_SELECTOR = '#wordlist';
-const STACK_SELECTOR = '#stack';
-const CALLSTACK_SELECTOR = '#callstack';
-const VARS_SELECTOR = '#vars';
-const SRC_SELECTOR = '#src';
-const IP_SELECTOR = '#wordlist .ip';
-
-function selectorForIP(word, offset) {
- return `#wordlist x-bytecode[x-index='${word}'] x-op[x-index='${offset}']`;
-}
-
-function wordlistElts(wordlist) {
- return wordlist.map((bc, i) => {
- const bcElt = document.createElement('x-bytecode');
- bcElt.setAttribute('x-index', i);
- bc.forEach((op, i) => {
- const opElt = document.createElement('x-op');
- opElt.setAttribute('x-index', i);
- opElt.textContent = op;
- bcElt.appendChild(opElt);
- })
- return bcElt;
- })
-}
-
-function initWordlist() {
- const sel = selectorForIP(0, 0);
- document.querySelectorAll(sel).forEach(e => {
- e.classList.add('ip')
- });
-}
-
-function renderStack(vmstack) {
- document.querySelectorAll(STACK_SELECTOR).forEach(e => {
- while (e.lastChild) {
- e.removeChild(e.lastChild);
- }
- vmstack.reverse()
- .forEach(datum => {
- const elt = document.createElement('li');
- elt.textContent = datum;
- e.appendChild(elt);
- return elt;
- });
- });
-}
-
-function renderCallStack(vmcallstack) {
- document.querySelectorAll(CALLSTACK_SELECTOR).forEach(e => {
- while (e.lastChild) {
- e.removeChild(e.lastChild);
- }
- vmcallstack.reverse()
- .forEach(datum => {
- const elt = document.createElement('li');
- elt.textContent = `${datum.word}@${datum.offset}`;
- e.appendChild(elt);
- return elt;
- });
- });
-}
-
-function renderVars(vmvars) {
- document.querySelectorAll(VARS_SELECTOR).forEach(e => {
- while (e.lastChild) {
- e.removeChild(e.lastChild);
- }
-
- ['out', 'heading', 'speed', 'doppler'].forEach(name => {
- const dt = document.createElement('dt');
- dt.textContent = name;
- e.appendChild(dt);
-
- const dd = document.createElement('dd');
- dd.textContent = vmvars[name];
- e.appendChild(dd);
- });
- });
-}
-
function clamp(radius, x, y, width, height) {
const xx = Math.min(Math.max(radius, x), width-radius);
const yy = Math.min(Math.max(radius, y), height-radius);
@@ -128,41 +46,6 @@ function renderArena(robos, delta=0) {
});
}
-const highRange = new Range();
-const highlight = new Highlight(highRange);
-CSS.highlights.set('exec', highlight);
-
-function renderTextHighlight(vm) {
- const ip = vm.ip;
- const anno = vm.annos[ip.word][ip.offset];
- const src = document.querySelector(SRC_SELECTOR);
-
- // this assumes the text node is the first child, maybe it isn't?
- highRange.setStart(src.childNodes[0], anno.start);
- highRange.setEnd(src.childNodes[0], anno.end);
-}
-
-function loadForth(taintedPath) {
- // ascii only + ‘-’, ‘_’, ‘.’, and ‘/’, but no ‘../’
- const path =
- taintedPath
- .replace(/[^-_A-Za-z./]/g, '')
- .replace(/\.\.\//g, '');
- fetch(`./samples/${path}`)
- .then(resp => {
- if (!resp.ok) {
- throw `http status ${resp.status}`
- }
- return resp.text()
- })
- .then(text => {
- document.querySelector(SRC_SELECTOR).textContent = text;
- })
- .catch(e => {
- console.error(`couldn't fetch ‘${path}’`, e);
- });
-}
-
async function loaded() {
const canvas = document.querySelector(CANVAS_SELECTOR);
const roboWorker = new Worker('robo.mjs', { type: 'module' });
@@ -181,30 +64,11 @@ async function loaded() {
switch (kind) {
case 'compile':
if (res) {
- let wordlistContainer = document.querySelector(WORDLIST_SELECTOR);
- const wordlist = wordlistElts(trans.wordlist);
- wordlist.forEach(elt => wordlistContainer.appendChild(elt));
- initWordlist();
- renderStack(trans.stack);
- renderCallStack(trans.callstack);
- renderVars(trans.vars);
- renderTextHighlight(trans);
-
renderArena([robo]);
+ document.querySelector('x-inspector').render(trans, true);
}
break;
case 'tick':
- const { word, offset } = trans.ip;
- document.querySelectorAll(IP_SELECTOR).forEach(e => e.classList.remove('ip'));
- const sel = selectorForIP(word, offset);
- document.querySelectorAll(sel).forEach(e => {
- e.classList.add('ip');
- });
- renderStack(trans.stack);
- renderCallStack(trans.callstack);
- renderVars(trans.vars);
- renderTextHighlight(trans);
-
robo.lastTick = document.timeline.currentTime;
const [x, y] = clamp(25, robo.x + robo.speedx, robo.y + robo.speedy, canvas.width, canvas.height);
@@ -220,6 +84,8 @@ async function loaded() {
].map(x => robo.speed * x);
robo.speedx = speedx;
robo.speedy = speedy;
+
+ document.querySelector('x-inspector').render(trans);
break;
default:
console.error('invalid message from robo worker', e.data);
@@ -229,26 +95,6 @@ async function loaded() {
console.error('error in roboWorker', e);
};
- document.querySelectorAll(SRC_SELECT_SELECTOR).forEach(sel => {
- sel.onchange = _ => loadForth(sel.value);
- loadForth(sel.value);
- });
-
- document.querySelector(COMPILE_BUTTON_SELECTOR).onclick = e => {
- console.debug('compile clicked', e);
-
- let wordlistContainer = document.querySelector(WORDLIST_SELECTOR);
- while (wordlistContainer.lastChild) {
- console.debug('removing child', wordlistContainer.lastChild)
- wordlistContainer.removeChild(wordlistContainer.lastChild);
- }
-
- // always add a newline until i decide what to do with the parser.
- const text = document.querySelector(SRC_SELECTOR).textContent + '\n';
- console.debug('compiling', text);
- roboWorker.postMessage({ kind: 'compile', text });
- };
-
document.querySelector(TICK_BUTTON_SELECTOR).onclick = e => {
console.debug('tick clicked', e);
roboWorker.postMessage({ kind: 'tick' });
@@ -307,6 +153,14 @@ async function loaded() {
document.querySelector(FPS_SELECTOR).textContent = 'n/a';
}
}
+
+ Inspector.register();
+ document.querySelectorAll(Inspector.name).forEach(elt => {
+ elt.addEventListener(Inspector.compileRequest, e => {
+ console.debug('compiling', e.detail.text);
+ roboWorker.postMessage({ kind: 'compile', text: e.detail.text });
+ });
+ });
}
document.addEventListener('DOMContentLoaded', loaded);