use crate::vm::vcell::VCell;
use crate::vm::Error;
use crate::vm::Error::InvalidStackIndex;
use log::trace;
use std::fmt::Display;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Stack {
stack: Vec<VCell>,
sp: usize,
}
impl Stack {
pub fn new() -> Stack {
Stack {
stack: vec![VCell::undefined(); 256],
sp: 0,
}
}
pub fn clear(&mut self) {
let size = self.stack.len();
self.stack = vec![VCell::undefined(); size];
}
pub fn iter(&self) -> impl Iterator<Item = &VCell> {
self.stack.iter()
}
pub fn get(&self, index: usize) -> Result<&VCell, Error> {
self.stack.get(index).ok_or(InvalidStackIndex(index))
}
pub fn get_mut(&mut self, index: usize) -> Result<&mut VCell, Error> {
self.stack.get_mut(index).ok_or(InvalidStackIndex(index))
}
pub fn get_offset(&self, offset: i64) -> Result<&VCell, Error> {
let index = (self.sp as i64 + offset) as usize;
self.stack.get(index).ok_or(InvalidStackIndex(index))
}
pub fn get_offset_mut(&mut self, offset: i64) -> Result<&mut VCell, Error> {
let index = (self.sp as i64 + offset) as usize;
self.stack.get_mut(index).ok_or(InvalidStackIndex(index))
}
pub fn get_sp(&self) -> usize {
self.sp
}
pub fn get_sp_mut(&mut self) -> &mut usize {
&mut self.sp
}
fn grow(&mut self) {
self.stack.resize(self.stack.len() * 2, VCell::Undefined);
}
pub fn len(&self) -> usize {
self.stack.len()
}
pub fn is_empty(&self) -> bool {
self.sp == 0
}
pub fn push<T: Into<VCell> + Display>(&mut self, vcell: T) {
match self.stack.get_mut(self.sp + 1) {
Some(slot) => {
*slot = vcell.into();
self.sp += 1;
}
None => {
self.grow();
self.push(vcell)
}
}
}
pub fn pop(&mut self) -> Result<&VCell, Error> {
return if self.sp > 0 {
self.sp -= 1;
self.stack
.get(self.sp + 1)
.ok_or_else(|| InvalidStackIndex(self.sp + 1))
} else {
Err(InvalidStackIndex(0))
};
}
pub fn trace(&self, start: usize, end: usize) {
for it in (start..end).rev() {
trace!(
"${:02x} = {}",
it,
self.get(it).unwrap_or(&VCell::Undefined)
);
}
}
}
impl Default for Stack {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stack_grows_on_push() {
let mut stack = Stack::new();
assert_eq!(stack.len(), 256);
for i in 0..1024 {
stack.push(VCell::FixedNum(i));
}
assert_eq!(stack.len(), 2048)
}
#[test]
fn relative_access() {
let mut stack = Stack::new();
stack.push(VCell::FixedNum(0));
stack.push(VCell::FixedNum(1));
stack.push(VCell::FixedNum(2));
assert_eq!(stack.get_offset(2), Ok(&VCell::Undefined));
assert_eq!(stack.get_offset(1), Ok(&VCell::Undefined));
assert_eq!(stack.get_offset(0), Ok(&VCell::FixedNum(2)));
assert_eq!(stack.get_offset(-1), Ok(&VCell::FixedNum(1)));
assert_eq!(stack.get_offset(-2), Ok(&VCell::FixedNum(0)));
assert_eq!(stack.get_offset(-3), Ok(&VCell::Undefined));
}
#[test]
fn push_and_pop() {
let mut stack = Stack::new();
stack.push(VCell::FixedNum(1));
stack.push(VCell::FixedNum(2));
assert_eq!(stack.pop(), Ok(&VCell::FixedNum(2)));
assert_eq!(stack.pop(), Ok(&VCell::FixedNum(1)));
assert_eq!(stack.pop(), Err(InvalidStackIndex(0)));
}
}