use std::{collections::HashMap, error::Error, fmt::Display};
use crate::ast;
use super::{FunctionInner, Object, ObjectInner};
#[derive(Debug)]
pub enum StackError {
PopEmptyFrame,
VariableNotInScope,
NoStack,
}
impl Display for StackError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::PopEmptyFrame => f.write_str("Could not pop stack frame because stack is empty!"),
Self::VariableNotInScope => f.write_str("Could not find variable in any stack"),
Self::NoStack => f.write_str("Could not perform operation since there are no stack frames."),
}
}
}
impl Error for StackError {}
type StackResult<T> = Result<T, StackError>;
type StackInner = Vec<HashMap<String, Object>>;
#[derive(Debug, Clone)]
pub struct Stack(StackInner);
impl Stack {
fn get(&self) -> &StackInner {
&self.0
}
fn get_mut(&mut self) -> &mut StackInner {
&mut self.0
}
pub fn new() -> Self {
Self(vec![HashMap::new()])
}
pub fn push_scope(&mut self) {
self.get_mut().push(HashMap::new())
}
pub fn pop_scope(&mut self) -> StackResult<()> {
self.get_mut().pop().map(|_| ()).ok_or(StackError::PopEmptyFrame)
}
pub fn load_params(&mut self, params: Vec<(String, Object)>) -> StackResult<()> {
for (name, val) in params.into_iter() {
self.create_var(name, val)?;
}
Ok(())
}
pub fn create_var(&mut self, name: String, val: Object) -> StackResult<()> {
let scope = self.get_mut().last_mut().ok_or(StackError::NoStack)?;
scope.insert(name, val);
Ok(())
}
pub fn get_var(&self, name: &str) -> StackResult<Object> {
for scope in self.get().iter().rev() {
if let Some(val) = scope.get(name) {
return Ok(val.clone());
}
}
Err(StackError::VariableNotInScope)
}
pub fn set_var(&mut self, name: &str, val: Object) -> StackResult<()> {
for scope in self.get_mut().iter_mut().rev() {
if let Some(obj) = scope.get_mut(name) {
*obj.inner() = val.inner().clone();
return Ok(())
}
}
Err(StackError::VariableNotInScope)
}
pub fn create_func(&mut self, name: String, ast: ast::Function) -> StackResult<()> {
let func = FunctionInner {
ast,
context: self.flat_copy()
};
let scope = self.get_mut().last_mut().ok_or(StackError::NoStack)?;
scope.insert(name, ObjectInner::FUNCTION(func).as_object());
Ok(())
}
pub fn flat_copy(&self) -> Self {
let mut stack = HashMap::new();
self.get().iter()
.for_each(|map| map.iter().for_each(|(k, v)| {
stack.insert(k.clone(), v.clone());
}));
Self(vec![stack])
}
}