From 0753ea2b9e10b0f5030b05e84cd8490cc9ec7b34 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Sat, 23 Aug 2025 13:05:07 -0400 Subject: highlight running code --- main.css | 4 ++++ main.mjs | 21 +++++++++++++++++++++ src/lib.rs | 28 ++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/main.css b/main.css index 15d721d..7a032cc 100644 --- a/main.css +++ b/main.css @@ -7,6 +7,10 @@ textarea { height: 25ex; } +#wordlist .ip { + background-color: yellow; +} + x-bytecode { display: block; } diff --git a/main.mjs b/main.mjs index bcb7f0a..7bc2ba4 100644 --- a/main.mjs +++ b/main.mjs @@ -14,6 +14,12 @@ function wordlistElts(wordlist) { }) } +function selectorForIP(word, offset) { + const sel = `#wordlist x-bytecode[x-index='${word}'] x-op[x-index='${offset}']`; + console.debug('using sel', sel); + return sel; +} + async function loaded() { console.debug('running init'); const mod = await init(); @@ -39,10 +45,25 @@ async function loaded() { if (res) { const wordlist = wordlistElts(interp.wordlist()); wordlist.forEach(elt => wordlistContainer.appendChild(elt)); + const sel = selectorForIP(0, 0); + document.querySelectorAll(sel).forEach(e => { + e.classList.add('ip') + }); } }; document.querySelector('#tick').onclick = e => { console.debug('tick clicked', e); + interp.tick(); + console.info('callstack', interp.callstack()); + console.info('stack', interp.stack()); + + const { word, offset } = interp.ip(); + console.info('ip', word, offset); + document.querySelectorAll('#wordlist .ip').forEach(e => e.classList.remove('ip')); + const sel = selectorForIP(word, offset); + document.querySelectorAll(sel).forEach(e => { + e.classList.add('ip') + }); }; document.querySelector('#run').onclick = e => { console.debug('run clicked', e); diff --git a/src/lib.rs b/src/lib.rs index 32a8ffc..840a86c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,12 @@ pub struct ExportedInstructionPointer { pub offset: usize, } +impl From<&forth::interp::InstructionPointer> for ExportedInstructionPointer { + fn from(ip: &forth::interp::InstructionPointer) -> Self { + Self { word: ip.word, offset: ip.offset } + } +} + // wasm can't wrap Vec>, so we need a custom type // - 23-aug-2025 #[wasm_bindgen] @@ -67,8 +73,12 @@ impl ExportedInterp { true } - pub fn tick(&mut self) { + pub fn tick(&mut self) -> Result { + let Some(interp) = &mut self.i else { + return Err("no interpreter".to_string()) + }; info!("executing single instruction"); + interp.tick().or_else(|err| Err(format!("runtime error: {:?}", err))) } pub fn run(&mut self) -> Result { @@ -98,15 +108,21 @@ impl ExportedInterp { interp.wordlist.iter().map(|bc| ExportedByteCode::from_bc(bc)).collect() } + pub fn callstack(&self) -> Vec { + let Some(interp) = &self.i else { + return vec![] + }; + info!("callstack: ‘{:?}’", interp.callstack); + interp.callstack.0.iter() + .map(|ip| ip.into()) + .collect() + } + pub fn ip(&self) -> ExportedInstructionPointer { let Some(interp) = self.i.as_ref() else { return ExportedInstructionPointer { word: 0, offset: 0 } }; - - ExportedInstructionPointer { - word: interp.ip.word, - offset: interp.ip.offset, - } + (&interp.ip).into() } } -- cgit v1.3