diff options
Diffstat (limited to 'site/main.mjs')
| -rw-r--r-- | site/main.mjs | 172 |
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); |
