summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@spork.org>2025-08-31 15:26:10 -0400
committerBrian Cully <bjc@spork.org>2025-08-31 15:26:10 -0400
commitf41f180655f35e1e3da7948d736894fcc4345d51 (patch)
treef43e4c428a0ae6480f929b2ddbcf9c4478f3a4f2
parent35c98bd145d42147520c61e8d5cf4985077daf29 (diff)
downloadautomathon-f41f180655f35e1e3da7948d736894fcc4345d51.tar.gz
automathon-f41f180655f35e1e3da7948d736894fcc4345d51.zip
rustfmt
-rw-r--r--src/forth/compiler.rs88
-rw-r--r--src/forth/vm.rs215
-rwxr-xr-xsrc/lib.rs47
-rw-r--r--tests/forth.rs2
4 files changed, 207 insertions, 145 deletions
diff --git a/src/forth/compiler.rs b/src/forth/compiler.rs
index e8aaa7f..b518b7e 100644
--- a/src/forth/compiler.rs
+++ b/src/forth/compiler.rs
@@ -82,12 +82,11 @@ impl<'a> Compiler<'a> {
// pull the next, whitespace-delimited word off the input stream.
fn next_word(&mut self) -> Option<(&'a str, usize, usize)> {
- let (start, _c) =
- self.enumerator.by_ref()
- .find(|(_i, c)| !c.is_whitespace())?;
- let (end, _c) =
- self.enumerator.by_ref()
- .find(|(_i, c)| c.is_whitespace())?;
+ let (start, _c) = self
+ .enumerator
+ .by_ref()
+ .find(|(_i, c)| !c.is_whitespace())?;
+ let (end, _c) = self.enumerator.by_ref().find(|(_i, c)| c.is_whitespace())?;
let word = &self.text[start..end];
Some((word, start, end))
}
@@ -126,7 +125,7 @@ impl<'a> Compiler<'a> {
let k = *i;
self.bc_mut().0.pop();
self.bc_mut().0.push(OpCode::TCall(k));
- },
+ }
Some(OpCode::If(t, f)) => {
let t = *t;
let f = *f;
@@ -134,7 +133,7 @@ impl<'a> Compiler<'a> {
self.bc_mut().0.push(OpCode::TIf(t, f));
// technically only needed if ‘f’ is None, but whatever.
//self.bc_push(OpCode::Ret, anno);
- },
+ }
_ => self.bc_push(OpCode::Ret, anno),
}
}
@@ -149,33 +148,33 @@ impl<'a> Compiler<'a> {
} else {
match word {
r#"s""# => {
- let (s_end, _) =
- self.enumerator
- .find(|(_i, c)| *c == '"')
- .ok_or(CompileError::MissingQuote)?;
- self.bc_push(OpCode::Str(end+1, s_end), anno);
- },
+ let (s_end, _) = self
+ .enumerator
+ .find(|(_i, c)| *c == '"')
+ .ok_or(CompileError::MissingQuote)?;
+ self.bc_push(OpCode::Str(end + 1, s_end), anno);
+ }
"(" => {
self.enumerator
.find(|(_i, c)| *c == ')')
.ok_or(CompileError::MissingParen)?;
- },
+ }
"\\" => {
self.enumerator
.find(|(_i, c)| *c == '\n')
.ok_or(CompileError::EOF)?;
- },
+ }
":" => {
let (name, _, _) = self.next_word().ok_or(CompileError::EOF)?;
self.wordalog.0.insert(name, self.wordlist.0.len());
self.defstack.push(self.wordlist.0.len());
self.wordlist.0.push(ByteCode(vec![]));
self.annotations.push(vec![]);
- },
+ }
";" => {
self.sub_tcall(anno);
self.defstack.pop().ok_or(CompileError::DefStackEmpty)?;
- },
+ }
"if" => {
let i = self.wordlist.0.len();
self.wordlist.0.push(ByteCode(vec![]));
@@ -183,7 +182,7 @@ impl<'a> Compiler<'a> {
self.defstack.push(i);
self.if_stack.push((IfClauses::True(i), anno));
- },
+ }
"else" => {
self.sub_tcall(anno);
self.defstack.pop();
@@ -195,11 +194,14 @@ impl<'a> Compiler<'a> {
let (true_clause, anno) = match self.if_stack.pop() {
None => return Err(CompileError::MissingIf),
- Some((IfClauses::TrueFalse(_, _), _)) => return Err(CompileError::MissingIf),
+ Some((IfClauses::TrueFalse(_, _), _)) => {
+ return Err(CompileError::MissingIf);
+ }
Some((IfClauses::True(cl), anno)) => (cl, anno),
};
- self.if_stack.push((IfClauses::TrueFalse(true_clause, i), anno));
- },
+ self.if_stack
+ .push((IfClauses::TrueFalse(true_clause, i), anno));
+ }
"then" => {
self.sub_tcall(anno);
self.defstack.pop();
@@ -208,12 +210,12 @@ impl<'a> Compiler<'a> {
None => return Err(CompileError::MissingIf),
Some((IfClauses::True(true_clause), anno)) => {
self.bc_push(OpCode::If(true_clause, None), anno);
- },
+ }
Some((IfClauses::TrueFalse(true_clause, false_clause), anno)) => {
self.bc_push(OpCode::If(true_clause, Some(false_clause)), anno);
}
}
- },
+ }
"+" => self.bc_push(OpCode::Add, anno),
"-" => self.bc_push(OpCode::Sub, anno),
"*" => self.bc_push(OpCode::Mul, anno),
@@ -237,8 +239,8 @@ impl<'a> Compiler<'a> {
#[cfg(test)]
mod tests {
- use super::*;
use super::super::vm::OpCode;
+ use super::*;
fn compiler_for(text: &str) -> Compiler {
let mut p = Compiler::new(text);
@@ -298,7 +300,11 @@ mod tests {
fn def_word() {
let comp = compiler_for(": add2 2 + ; 3 add2\n");
let main = &comp.wordlist.0[0];
- let add2_index = comp.wordalog.0.get("add2").expect("add2 has entry in wordlist");
+ let add2_index = comp
+ .wordalog
+ .0
+ .get("add2")
+ .expect("add2 has entry in wordlist");
assert_eq!(main, vec![OpCode::Num(3), OpCode::Call(*add2_index)]);
let add2 = &comp.wordlist.0[*add2_index];
@@ -313,7 +319,10 @@ mod tests {
let main = &comp.wordlist.0[0];
assert_eq!(main, vec![OpCode::If(1, None)]);
let tr = &comp.wordlist.0[1];
- assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]);
+ assert_eq!(
+ tr,
+ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]
+ );
}
#[test]
@@ -326,9 +335,15 @@ mod tests {
assert_eq!(main[0], OpCode::If(1, Some(2)));
assert_eq!(main, vec![OpCode::If(1, Some(2))]);
let tr = &comp.wordlist.0[1];
- assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]);
+ assert_eq!(
+ tr,
+ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]
+ );
let fl = &comp.wordlist.0[2];
- assert_eq!(fl, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret]);
+ assert_eq!(
+ fl,
+ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret]
+ );
}
#[test]
@@ -354,7 +369,10 @@ mod tests {
let t = &comp.wordlist.0[1];
assert_eq!(t, vec![OpCode::TIf(2, None)]);
let tr = &comp.wordlist.0[2];
- assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]);
+ assert_eq!(
+ tr,
+ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]
+ );
}
#[test]
@@ -367,9 +385,15 @@ mod tests {
let t = &comp.wordlist.0[1];
assert_eq!(t, vec![OpCode::TIf(2, Some(3))]);
let tr = &comp.wordlist.0[2];
- assert_eq!(tr, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]);
+ assert_eq!(
+ tr,
+ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Add, OpCode::Ret]
+ );
let fl = &comp.wordlist.0[3];
- assert_eq!(fl, vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret]);
+ assert_eq!(
+ fl,
+ vec![OpCode::Num(1), OpCode::Num(2), OpCode::Sub, OpCode::Ret]
+ );
}
#[test]
diff --git a/src/forth/vm.rs b/src/forth/vm.rs
index 5bc1835..4930514 100644
--- a/src/forth/vm.rs
+++ b/src/forth/vm.rs
@@ -54,8 +54,7 @@ impl ByteCode {
// it there.
impl PartialEq<Vec<OpCode>> for &ByteCode {
fn eq(&self, other: &Vec<OpCode>) -> bool {
- self.0.len() == other.len() &&
- std::iter::zip(&self.0, other).all(|(a, b)| a == b)
+ self.0.len() == other.len() && std::iter::zip(&self.0, other).all(|(a, b)| a == b)
}
}
@@ -75,10 +74,7 @@ pub struct InstructionPointer {
impl InstructionPointer {
pub fn new() -> Self {
- Self {
- word: 0,
- offset: 0,
- }
+ Self { word: 0, offset: 0 }
}
}
@@ -155,116 +151,114 @@ impl VM {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.0.push(n2 + n1);
- },
+ }
OpCode::Sub => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.0.push(n2 - n1);
- },
+ }
OpCode::Mul => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.0.push(n2 * n1);
- },
+ }
OpCode::Div => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
self.stack.0.push(n2 / n1);
- },
+ }
OpCode::Dup => {
let len = self.stack.0.len();
if len < 1 {
- return Err(RuntimeError::StackUnderflow)
+ return Err(RuntimeError::StackUnderflow);
}
- self.stack.0.push(self.stack.0[len-1]);
- },
+ self.stack.0.push(self.stack.0[len - 1]);
+ }
OpCode::Drop => {
self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
- },
+ }
OpCode::Swap => {
let top = self.stack.0.len() - 1;
if top < 1 {
- return Err(RuntimeError::StackUnderflow)
+ return Err(RuntimeError::StackUnderflow);
}
- let (a, b) =
- self.stack.0.split_at_mut(top);
- std::mem::swap(&mut a[top-1], &mut b[0]);
- },
+ let (a, b) = self.stack.0.split_at_mut(top);
+ std::mem::swap(&mut a[top - 1], &mut b[0]);
+ }
OpCode::Rot => {
let top = self.stack.0.len() - 1;
if top < 2 {
- return Err(RuntimeError::StackUnderflow)
+ return Err(RuntimeError::StackUnderflow);
}
- let (a, b) =
- self.stack.0.split_at_mut(top);
- std::mem::swap(&mut a[top-1], &mut b[0]);
- std::mem::swap(&mut a[top-2], &mut b[0]);
- },
+ let (a, b) = self.stack.0.split_at_mut(top);
+ std::mem::swap(&mut a[top - 1], &mut b[0]);
+ std::mem::swap(&mut a[top - 2], &mut b[0]);
+ }
OpCode::EQ => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let v = if n2 == n1 { -1 } else { 0 };
self.stack.0.push(v);
- },
+ }
OpCode::GT => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let v = if n2 > n1 { -1 } else { 0 };
self.stack.0.push(v);
- },
+ }
OpCode::GTE => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let v = if n2 >= n1 { -1 } else { 0 };
self.stack.0.push(v);
- },
+ }
OpCode::LT => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let v = if n2 < n1 { -1 } else { 0 };
self.stack.0.push(v);
- },
+ }
OpCode::LTE => {
let n1 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let n2 = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
let v = if n2 <= n1 { -1 } else { 0 };
self.stack.0.push(v);
- },
+ }
OpCode::Ret => {
self.ip = self.callstack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
- },
+ }
OpCode::Call(i) => {
self.call(i);
// skip the offset increment
- return Ok(true)
- },
+ return Ok(true);
+ }
OpCode::TCall(i) => {
self.jmp(i);
// skip the offset increment
- return Ok(true)
- },
+ return Ok(true);
+ }
OpCode::If(true_clause, false_clause) => {
let flag = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
if flag != 0 {
self.call(true_clause);
- return Ok(true)
+ return Ok(true);
} else if let Some(false_clause) = false_clause {
self.call(false_clause);
- return Ok(true)
+ return Ok(true);
}
- },
+ }
OpCode::TIf(true_clause, false_clause) => {
let flag = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
if flag != 0 {
self.jmp(true_clause);
- return Ok(true)
+ return Ok(true);
} else if let Some(false_clause) = false_clause {
self.jmp(false_clause);
- return Ok(true)
+ return Ok(true);
} else {
self.ip = self.callstack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
}
- },
+ }
}
self.ip.offset += 1;
Ok(self.ip.offset < self.wordlist.0[self.ip.word].len())
@@ -272,38 +266,52 @@ impl VM {
pub fn run(&mut self) -> Result<usize, RuntimeError> {
let mut count = 0;
- while self.tick()? { count += 1 }
+ while self.tick()? {
+ count += 1
+ }
Ok(count)
}
}
#[cfg(test)]
mod tests {
- use super::*;
use super::OpCode;
+ use super::*;
fn wl_for(v: Vec<Vec<OpCode>>) -> WordList {
- WordList(v.into_iter()
- .map(|x| ByteCode(x))
- .collect())
+ WordList(v.into_iter().map(|x| ByteCode(x)).collect())
}
#[test]
fn simple_ticks() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Num(3), OpCode::Add]));
+ wordlist
+ .0
+ .push(ByteCode(vec![OpCode::Num(2), OpCode::Num(3), OpCode::Add]));
let mut vm = VM::new(wordlist);
- assert_eq!(vm.tick().expect("should execute instruction"), true, "first arg running");
+ assert_eq!(
+ vm.tick().expect("should execute instruction"),
+ true,
+ "first arg running"
+ );
assert_eq!(vm.ip.word, 0);
assert_eq!(vm.ip.offset, 1);
assert_eq!(vm.stack.0.len(), 1);
assert_eq!(vm.stack.0[0], 2, "first argument");
- assert_eq!(vm.tick().expect("should execute instruction"), true, "second arg running");
+ assert_eq!(
+ vm.tick().expect("should execute instruction"),
+ true,
+ "second arg running"
+ );
assert_eq!(vm.ip.word, 0);
assert_eq!(vm.ip.offset, 2);
assert_eq!(vm.stack.0.len(), 2);
assert_eq!(vm.stack.0[1], 3, "second argument");
- assert_eq!(vm.tick().expect("should execute instruction"), false, "stopped after addition");
+ assert_eq!(
+ vm.tick().expect("should execute instruction"),
+ false,
+ "stopped after addition"
+ );
assert_eq!(vm.ip.word, 0);
assert_eq!(vm.ip.offset, 3);
assert_eq!(vm.stack.0.len(), 1);
@@ -314,14 +322,17 @@ mod tests {
fn custom_word() {
let mut wordlist = WordList(vec![]);
wordlist.0.push(ByteCode(vec![
- OpCode::Num(2), OpCode::Num(3), OpCode::Call(1), OpCode::Num(-2), OpCode::Add,
- OpCode::Sub, OpCode::Ret,
+ OpCode::Num(2),
+ OpCode::Num(3),
+ OpCode::Call(1),
+ OpCode::Num(-2),
+ OpCode::Add,
+ OpCode::Sub,
+ OpCode::Ret,
]));
let mut vm = VM::new(wordlist);
// "sub" definition
- vm.wordlist.0.push(ByteCode(vec![
- OpCode::Sub, OpCode::Ret,
- ]));
+ vm.wordlist.0.push(ByteCode(vec![OpCode::Sub, OpCode::Ret]));
vm.tick().expect("should execute instruction");
assert_eq!(vm.ip.word, 0);
@@ -367,7 +378,9 @@ mod tests {
fn tail_call() {
let mut wordlist = WordList(vec![]);
wordlist.0.push(ByteCode(vec![OpCode::Call(1)]));
- wordlist.0.push(ByteCode(vec![OpCode::TCall(2), OpCode::Ret]));
+ wordlist
+ .0
+ .push(ByteCode(vec![OpCode::TCall(2), OpCode::Ret]));
wordlist.0.push(ByteCode(vec![OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -382,7 +395,11 @@ mod tests {
#[test]
fn if_then_true() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::If(1, None), OpCode::Num(0)]));
+ wordlist.0.push(ByteCode(vec![
+ OpCode::Num(-1),
+ OpCode::If(1, None),
+ OpCode::Num(0),
+ ]));
wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -405,7 +422,11 @@ mod tests {
#[test]
fn if_then_false() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Num(0), OpCode::If(1, None), OpCode::Num(-1)]));
+ wordlist.0.push(ByteCode(vec![
+ OpCode::Num(0),
+ OpCode::If(1, None),
+ OpCode::Num(-1),
+ ]));
wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -422,7 +443,11 @@ mod tests {
#[test]
fn if_else_then_true() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::If(1, Some(2)), OpCode::Num(-2)]));
+ wordlist.0.push(ByteCode(vec![
+ OpCode::Num(-1),
+ OpCode::If(1, Some(2)),
+ OpCode::Num(-2),
+ ]));
wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -446,7 +471,11 @@ mod tests {
#[test]
fn if_else_then_false() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Num(0), OpCode::If(1, Some(2)), OpCode::Num(-2)]));
+ wordlist.0.push(ByteCode(vec![
+ OpCode::Num(0),
+ OpCode::If(1, Some(2)),
+ OpCode::Num(-2),
+ ]));
wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -470,8 +499,14 @@ mod tests {
#[test]
fn tail_if_then_true() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Call(1), OpCode::Num(0)]));
- wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::TIf(2, None), OpCode::Ret]));
+ wordlist
+ .0
+ .push(ByteCode(vec![OpCode::Call(1), OpCode::Num(0)]));
+ wordlist.0.push(ByteCode(vec![
+ OpCode::Num(-1),
+ OpCode::TIf(2, None),
+ OpCode::Ret,
+ ]));
wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -515,8 +550,14 @@ mod tests {
#[test]
fn tail_if_else_then_true() {
let mut wordlist = WordList(vec![]);
- wordlist.0.push(ByteCode(vec![OpCode::Call(1), OpCode::Num(-2)]));
- wordlist.0.push(ByteCode(vec![OpCode::Num(-1), OpCode::TIf(2, Some(3)), OpCode::Ret]));
+ wordlist
+ .0
+ .push(ByteCode(vec![OpCode::Call(1), OpCode::Num(-2)]));
+ wordlist.0.push(ByteCode(vec![
+ OpCode::Num(-1),
+ OpCode::TIf(2, Some(3)),
+ OpCode::Ret,
+ ]));
wordlist.0.push(ByteCode(vec![OpCode::Num(1), OpCode::Ret]));
wordlist.0.push(ByteCode(vec![OpCode::Num(2), OpCode::Ret]));
let mut vm = VM::new(wordlist);
@@ -541,12 +582,17 @@ mod tests {
#[test]
fn tail_if_else_then_false() {
- let wordlist = WordList(vec![
- vec![OpCode::Call(1), OpCode::Num(-2)],
- vec![OpCode::Num(0), OpCode::TIf(2, Some(3)), OpCode::Ret],
- vec![OpCode::Num(1), OpCode::Ret],
- vec![OpCode::Num(2), OpCode::Ret],
- ].into_iter().map(|x| ByteCode(x)).collect());
+ let wordlist = WordList(
+ vec![
+ vec![OpCode::Call(1), OpCode::Num(-2)],
+ vec![OpCode::Num(0), OpCode::TIf(2, Some(3)), OpCode::Ret],
+ vec![OpCode::Num(1), OpCode::Ret],
+ vec![OpCode::Num(2), OpCode::Ret],
+ ]
+ .into_iter()
+ .map(|x| ByteCode(x))
+ .collect(),
+ );
let mut vm = VM::new(wordlist);
vm.tick().expect("should execute instruction");
@@ -565,9 +611,7 @@ mod tests {
#[test]
fn opcode_dup() {
- let wordlist = wl_for(vec![
- vec![OpCode::Num(1), OpCode::Dup],
- ]);
+ let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Dup]]);
let mut vm = VM::new(wordlist);
vm.run().expect("should run to completion");
assert_eq!(vm.stack.0, vec![1, 1]);
@@ -575,18 +619,14 @@ mod tests {
#[test]
fn opcode_dup_underflow() {
- let wordlist = wl_for(vec![
- vec![OpCode::Dup],
- ]);
+ let wordlist = wl_for(vec![vec![OpCode::Dup]]);
let mut vm = VM::new(wordlist);
assert!(vm.run().is_err_and(|e| e == RuntimeError::StackUnderflow));
}
#[test]
fn opcode_swap() {
- let wordlist = wl_for(vec![
- vec![OpCode::Num(1), OpCode::Num(2), OpCode::Swap],
- ]);
+ let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Num(2), OpCode::Swap]]);
let mut vm = VM::new(wordlist);
vm.run().expect("should run to completion");
assert_eq!(vm.stack.0, vec![2, 1]);
@@ -594,18 +634,19 @@ mod tests {
#[test]
fn opcode_swap_underflow() {
- let wordlist = wl_for(vec![
- vec![OpCode::Num(1), OpCode::Swap],
- ]);
+ let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Swap]]);
let mut vm = VM::new(wordlist);
assert!(vm.run().is_err_and(|e| e == RuntimeError::StackUnderflow));
}
#[test]
fn opcode_rot() {
- let wordlist = wl_for(vec![
- vec![OpCode::Num(1), OpCode::Num(2), OpCode::Num(3), OpCode::Rot],
- ]);
+ let wordlist = wl_for(vec![vec![
+ OpCode::Num(1),
+ OpCode::Num(2),
+ OpCode::Num(3),
+ OpCode::Rot,
+ ]]);
let mut vm = VM::new(wordlist);
vm.run().expect("should run to completion");
assert_eq!(vm.stack.0, vec![2, 3, 1]);
@@ -613,9 +654,7 @@ mod tests {
#[test]
fn opcode_rot_underflow() {
- let wordlist = wl_for(vec![
- vec![OpCode::Num(1), OpCode::Num(2), OpCode::Rot],
- ]);
+ let wordlist = wl_for(vec![vec![OpCode::Num(1), OpCode::Num(2), OpCode::Rot]]);
let mut vm = VM::new(wordlist);
assert!(vm.run().is_err_and(|e| e == RuntimeError::StackUnderflow));
}
diff --git a/src/lib.rs b/src/lib.rs
index 27ff2f4..8aeaaff 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,7 +12,10 @@ pub struct ExportedInstructionPointer {
impl From<&forth::vm::InstructionPointer> for ExportedInstructionPointer {
fn from(ip: &forth::vm::InstructionPointer) -> Self {
- Self { word: ip.word, offset: ip.offset }
+ Self {
+ word: ip.word,
+ offset: ip.offset,
+ }
}
}
@@ -108,21 +111,25 @@ pub struct ExportedVM {
#[wasm_bindgen]
impl ExportedVM {
fn new() -> Self {
- Self { annos: vec![], vm: None }
+ Self {
+ annos: vec![],
+ vm: None,
+ }
}
pub fn compile(&mut self, text: &str) -> bool {
let mut comp = forth::compiler::Compiler::new(text);
if let Err(e) = comp.compile() {
error!("couldn't compile program text: {e:?}");
- return false
+ return false;
}
- self.annos =
- comp.annotations.iter()
- .map(|word_anno| -> ExportedWordAnnotations {
- word_anno.iter().map(|a| a.into()).collect()
- })
- .collect();
+ self.annos = comp
+ .annotations
+ .iter()
+ .map(|word_anno| -> ExportedWordAnnotations {
+ word_anno.iter().map(|a| a.into()).collect()
+ })
+ .collect();
let vm = forth::vm::VM::new(comp.wordlist);
let _ = self.vm.insert(vm);
true
@@ -130,14 +137,14 @@ impl ExportedVM {
pub fn tick(&mut self) -> Result<bool, String> {
let Some(vm) = &mut self.vm else {
- return Err("no vm".to_string())
+ return Err("no vm".to_string());
};
vm.tick().map_err(|err| format!("runtime error: {err:?}"))
}
pub fn run(&mut self) -> Result<usize, String> {
let Some(vm) = &mut self.vm else {
- return Err("no vm".to_string())
+ return Err("no vm".to_string());
};
vm.ip.word = 0;
@@ -146,17 +153,13 @@ impl ExportedVM {
}
pub fn stack(&self) -> Vec<forth::vm::DataStackType> {
- let Some(vm) = &self.vm else {
- return vec![]
- };
+ let Some(vm) = &self.vm else { return vec![] };
vm.stack.0.clone()
}
pub fn wordlist(&self) -> Vec<ExportedByteCode> {
- let Some(vm) = &self.vm else {
- return vec![]
- };
+ let Some(vm) = &self.vm else { return vec![] };
vm.wordlist.iter().map(|bc| bc.into()).collect()
}
@@ -170,17 +173,13 @@ impl ExportedVM {
}
pub fn callstack(&self) -> Vec<ExportedInstructionPointer> {
- let Some(vm) = &self.vm else {
- return vec![]
- };
- vm.callstack.0.iter()
- .map(|ip| ip.into())
- .collect()
+ let Some(vm) = &self.vm else { return vec![] };
+ vm.callstack.0.iter().map(|ip| ip.into()).collect()
}
pub fn ip(&self) -> ExportedInstructionPointer {
let Some(vm) = &self.vm else {
- return ExportedInstructionPointer { word: 0, offset: 0 }
+ return ExportedInstructionPointer { word: 0, offset: 0 };
};
(&vm.ip).into()
}
diff --git a/tests/forth.rs b/tests/forth.rs
index d9cbed4..2538419 100644
--- a/tests/forth.rs
+++ b/tests/forth.rs
@@ -1,6 +1,6 @@
use automathon::forth::{
compiler::Compiler,
- vm::{WordList, VM},
+ vm::{VM, WordList},
};
fn compiler_for(text: &str) -> Compiler {