use crate::memory::object_map::Memory;
use crate::{errors::RuntimeError, memory::vm_data::VMData, RuntimeResult};
use std::fmt::Display;
use std::ops::Index;
const STACK_SIZE: usize = 16 * 16384 / size_of::<VMData>();
#[derive(Debug)]
pub struct Stack {
values: [VMData; STACK_SIZE],
pub top: usize,
}
impl Default for Stack {
fn default() -> Self {
Self::new()
}
}
impl Stack {
pub fn new() -> Self {
Self {
values: [VMData::new_unit(); STACK_SIZE],
top: 0,
}
}
pub fn push(&mut self, val: VMData) -> Result<(), RuntimeError> {
if self.top < STACK_SIZE {
self.values[self.top] = val;
self.top += 1;
Ok(())
} else {
Err(RuntimeError::StackOverflow)
}
}
pub fn push_with_rc(&mut self, val: VMData, mem: &mut Memory) -> Result<(), RuntimeError> {
if self.top < STACK_SIZE {
self.values[self.top] = val;
match val.tag {
VMData::TAG_OBJECT | VMData::TAG_LIST | VMData::TAG_STR => {
mem.rc_inc(val.as_object());
}
_ => {}
}
self.top += 1;
Ok(())
} else {
Err(RuntimeError::StackOverflow)
}
}
#[inline(always)]
pub fn truncate(&mut self, new_top: usize, mem: &mut Memory) -> RuntimeResult<()> {
for i in new_top..=self.top {
match self.values[i].tag {
VMData::TAG_OBJECT | VMData::TAG_LIST | VMData::TAG_STR => {
mem.rc_dec(self.values[i].as_object())?;
}
_ => {}
}
}
self.top = new_top;
Ok(())
}
pub fn pop(&mut self) -> Result<VMData, RuntimeError> {
if self.top != 0 {
self.top -= 1;
Ok(self.values[self.top])
} else {
Err(RuntimeError::StackUnderflow)
}
}
pub fn pop_with_rc(&mut self, mem: &mut Memory) -> Result<VMData, RuntimeError> {
if self.top != 0 {
self.top -= 1;
let r = self.values[self.top];
match r.tag {
VMData::TAG_OBJECT | VMData::TAG_LIST | VMData::TAG_STR => {
mem.rc_dec(r.as_object())?;
}
_ => {}
}
Ok(r)
} else {
Err(RuntimeError::StackUnderflow)
}
}
#[inline(always)]
pub fn last(&self) -> Result<&VMData, RuntimeError> {
if self.top != 0 {
Ok(&self.values[self.top - 1])
} else {
Err(RuntimeError::StackUnderflow)
}
}
pub fn extends(&mut self, values: &[VMData]) -> Result<(), RuntimeError> {
if self.top + values.len() < STACK_SIZE {
for val in values {
self.values[self.top] = *val;
self.top += 1;
}
Ok(())
} else {
Err(RuntimeError::StackOverflow)
}
}
pub fn push_object(&mut self, _obj: &[VMData]) -> Result<(), RuntimeError> {
unimplemented!("push_object(&mut self, obj: &[VMData])")
}
pub fn new_stack_frame(&mut self) {}
pub fn set(&mut self, _offset: usize) {}
pub fn iter(&self) -> std::slice::Iter<VMData> {
self.values[..self.top].iter()
}
}
impl IntoIterator for Stack {
type Item = VMData;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values[..self.top].to_vec().into_iter()
}
}
impl Index<usize> for Stack {
type Output = VMData;
fn index(&self, index: usize) -> &Self::Output {
&self.values[index]
}
}
impl Display for Stack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Stack: {{ values: {}, top: {}}}",
{
let mut s = "[".to_string();
for i in 0..=self.top {
s.push_str(&format!("{}, ", self.values[i]))
}
s.push(']');
s
},
self.top
)
}
}