summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@spork.org>2025-08-23 13:05:07 -0400
committerBrian Cully <bjc@spork.org>2025-08-23 13:05:07 -0400
commit0753ea2b9e10b0f5030b05e84cd8490cc9ec7b34 (patch)
tree78750e55c5839ffb9c703a3848b04718e8e11b61
parent8ce858ce7a03090b3b2a1310d17b1206f097637f (diff)
downloadautomathon-0753ea2b9e10b0f5030b05e84cd8490cc9ec7b34.tar.gz
automathon-0753ea2b9e10b0f5030b05e84cd8490cc9ec7b34.zip
highlight running code
-rw-r--r--main.css4
-rw-r--r--main.mjs21
-rwxr-xr-xsrc/lib.rs28
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<Vec<String>>, 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<bool, String> {
+ 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<usize, String> {
@@ -98,15 +108,21 @@ impl ExportedInterp {
interp.wordlist.iter().map(|bc| ExportedByteCode::from_bc(bc)).collect()
}
+ pub fn callstack(&self) -> Vec<ExportedInstructionPointer> {
+ 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()
}
}