use super::{ast::Variable, error::VariableError, typed::Type}; #[derive(Debug, Default)] pub struct Context { vars: Vec, unguard_points: Vec, } impl Context { pub fn new() -> Self { Self::default() } pub fn depth(&self) -> usize { self.vars.len() } pub fn is_unguarded(&self, var: &Variable) -> Option { if self.vars.len() <= var.index() { None } else if self.unguard_points.is_empty() { Some(false) } else { Some( self.unguard_points[self.unguard_points.len() - 1] + var.index() >= self.vars.len(), ) } } pub fn with_unguard R, R>(&mut self, f: F) -> R { self.unguard_points.push(self.vars.len()); let res = f(self); self.unguard_points.pop(); res } pub fn get_variable_type(&self, var: &Variable) -> Result<&Type, VariableError> { match self.is_unguarded(var) { None => Err(VariableError::FreeVariable(var.clone())), Some(false) => Err(VariableError::GuardedVariable(var.clone())), Some(true) => Ok(&self.vars[self.vars.len() - var.index() - 1]), } } pub fn with_variable_type R, R>(&mut self, ty: Type, f: F) -> R { self.vars.push(ty); let res = f(self); self.vars.pop(); res } }