loading...

Building a stack-based virtual machine, part 2 - the stack

jimsy profile image James Harton ・Updated on ・2 min read

You'll note that in part one there wasn't really any code. Sorry about that. Let's fix that now.

If you want to jump to the end the completed source code for stack-vm is on Gitlab.

The first thing we need to build a stack machine is a stack: a data structure that we can push and pop operands into/out of. Because we're using Rust that means we're going to use a Vector and we need it to be generic.

pub struct Stack<T>(Vec<T>)

impl<T> Stack<T> {
  pub fn new() -> Stack<T> {
    Stack(vec![])
  }

  pub fn is_empty(&self) -> bool {
    self.0.is_empty()
  }

  pub fn push(&mut self, value: T) {
    self.0.push(value);
  }

  pub fn pop(&mut self) -> T {
    self.0.pop().expect("Unable to pop from empty stack")
  }
}
Enter fullscreen mode Exit fullscreen mode

This gives us a generic stack which can only be pushed and popped. We also added is_empty to make testing a little easier. Speaking of testing, here's the tests. Note that in our tests we make this a usize stack to make it nice and easy to work with.

#[cfg(test)]
mod test {
  use super::*;

    #[test]
    fn new() {
        let stack: Stack<usize> = Stack::new();
        assert!(stack.is_empty());
    }

    #[test]
    fn push() {
        let mut stack: Stack<usize> = Stack::new();
        stack.push(13);
        assert!(!stack.is_empty());
    }

    #[test]
    fn pop() {
        let mut stack: Stack<usize> = Stack::new();
        stack.push(13);
        let value = stack.pop();
        assert_eq!(value, 13);
    }

    #[test]
    #[should_panic(expected = "empty stack")]
    fn empty_pop() {
        let mut stack: Stack<usize> = Stack::new();
        stack.pop();
    }

}
Enter fullscreen mode Exit fullscreen mode

In the next instalment we will figure out what an instruction is, how to build one and make a nice table to store them in.

Discussion

pic
Editor guide