summaryrefslogtreecommitdiffstats
path: root/src/forth
diff options
context:
space:
mode:
Diffstat (limited to 'src/forth')
-rw-r--r--src/forth/vm.rs111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/forth/vm.rs b/src/forth/vm.rs
index ad4b78c..e7c3794 100644
--- a/src/forth/vm.rs
+++ b/src/forth/vm.rs
@@ -33,6 +33,17 @@ pub enum OpCode {
// which are bounded, so running of the end can be treated as an
// implicit ‘ret’.
Ret,
+
+ // robo-specific stuff
+ //
+ // todo: figure out how to split this out of the compiler/vm and
+ // provide it as some kind of plugin.
+ Say,
+ Heading,
+ SetHeading,
+ Velocity,
+ SetVelocity,
+ Doppler,
}
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -110,6 +121,11 @@ pub struct VM {
pub callstack: CallStack,
pub wordlist: WordList,
pub ip: InstructionPointer,
+
+ pub out: Vec<String>,
+ pub heading: DataStackType,
+ pub velocity: DataStackType,
+ pub doppler: DataStackType,
}
#[derive(Debug, PartialEq, Eq)]
@@ -132,6 +148,11 @@ impl VM {
callstack: CallStack(Vec::new()),
ip: InstructionPointer::new(),
wordlist,
+
+ out: vec![],
+ heading: 0,
+ velocity: 0,
+ doppler: 0,
}
}
@@ -286,6 +307,25 @@ impl VM {
self.ip = self.callstack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
}
}
+ OpCode::Say => {
+ let v = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
+ self.out.push(format!("{}", v));
+ }
+ OpCode::Heading => {
+ self.stack.0.push(self.heading);
+ }
+ OpCode::SetHeading => {
+ self.heading = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
+ }
+ OpCode::Velocity => {
+ self.stack.0.push(self.velocity);
+ }
+ OpCode::SetVelocity => {
+ self.velocity = self.stack.0.pop().ok_or(RuntimeError::StackUnderflow)?;
+ }
+ OpCode::Doppler => {
+ self.stack.0.push(self.doppler);
+ }
}
self.ip.offset += 1;
Ok(self.ip.offset < self.wordlist.0[self.ip.word].len())
@@ -767,4 +807,75 @@ mod tests {
assert_eq!(vm.stack.0, vec![res]);
}
}
+
+
+ #[test]
+ fn opcode_say() {
+ let wordlist = wl_for(vec![vec![
+ OpCode::Num(-1), OpCode::Say
+ ]]);
+ let mut vm = VM::new(wordlist);
+ vm.run().expect("should run to completion");
+ assert_eq!(vm.stack.0.len(), 0, "empty stack");
+ assert_eq!(vm.out.len(), 1, "output length");
+ assert_eq!(vm.out[0], "-1", "output value");
+ }
+
+ #[test]
+ fn opcode_heading() {
+ let wordlist = wl_for(vec![vec![
+ OpCode::Heading
+ ]]);
+ let mut vm = VM::new(wordlist);
+ vm.heading = 12;
+ vm.run().expect("should run to completion");
+ assert_eq!(vm.stack.0.len(), 1, "stack size");
+ assert_eq!(vm.stack.0[0], 12, "heading value");
+ }
+
+ #[test]
+ fn opcode_setheading() {
+ let wordlist = wl_for(vec![vec![
+ OpCode::Num(3), OpCode::SetHeading
+ ]]);
+ let mut vm = VM::new(wordlist);
+ vm.run().expect("should run to completion");
+ assert_eq!(vm.stack.0.len(), 0, "empty stack");
+ assert_eq!(vm.heading, 3, "heading value");
+ }
+
+ #[test]
+ fn opcode_velocity() {
+ let wordlist = wl_for(vec![vec![
+ OpCode::Velocity
+ ]]);
+ let mut vm = VM::new(wordlist);
+ vm.velocity = 12;
+ vm.run().expect("should run to completion");
+ assert_eq!(vm.stack.0.len(), 1, "stack size");
+ assert_eq!(vm.stack.0[0], 12, "velocity value");
+ }
+
+ #[test]
+ fn opcode_setvelocity() {
+ let wordlist = wl_for(vec![vec![
+ OpCode::Num(3), OpCode::SetVelocity
+ ]]);
+ let mut vm = VM::new(wordlist);
+ vm.run().expect("should run to completion");
+ assert_eq!(vm.stack.0.len(), 0, "empty stack");
+ assert_eq!(vm.velocity, 3, "velocity value");
+ }
+
+ #[test]
+ fn opcode_doppler() {
+ let wordlist = wl_for(vec![vec![
+ OpCode::Doppler
+ ]]);
+ let mut vm = VM::new(wordlist);
+ vm.doppler = 12;
+ vm.run().expect("should run to completion");
+ assert_eq!(vm.stack.0.len(), 1, "stack size");
+ assert_eq!(vm.stack.0[0], 12, "doppler value");
+ }
}