summaryrefslogtreecommitdiff
path: root/src/chomp/context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/chomp/context.rs')
-rw-r--r--src/chomp/context.rs51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/chomp/context.rs b/src/chomp/context.rs
new file mode 100644
index 0000000..392023f
--- /dev/null
+++ b/src/chomp/context.rs
@@ -0,0 +1,51 @@
+use super::{ast::Variable, error::VariableError, typed::Type};
+
+#[derive(Debug, Default)]
+pub struct Context {
+ vars: Vec<Type>,
+ unguard_points: Vec<usize>,
+}
+
+impl Context {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn depth(&self) -> usize {
+ self.vars.len()
+ }
+
+ pub fn is_unguarded(&self, var: &Variable) -> Option<bool> {
+ 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<F: FnOnce(&mut Self) -> 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<F: FnOnce(&mut Self) -> R, R>(&mut self, ty: Type, f: F) -> R {
+ self.vars.push(ty);
+ let res = f(self);
+ self.vars.pop();
+ res
+ }
+}