use std::collections::{HashMap, HashSet};
use crate::check::constrain::constraint::builder::{format_var_map, VarMapping};
use crate::check::constrain::constraint::expected::Expected;
use crate::check::name::string_name::StringName;
use crate::check::name::true_name::TrueName;
#[derive(Clone, Debug, Default)]
pub struct Environment {
pub in_loop: bool,
pub in_fun: bool,
pub is_expr: bool,
pub is_def_mode: bool,
pub is_destruct_mode: bool,
pub return_type: Option<Expected>,
pub raises_caught: HashSet<TrueName>,
pub class: Option<StringName>,
pub unassigned: HashSet<String>,
pub vars: HashMap<String, HashSet<(bool, Expected)>>,
pub var_mapping: VarMapping,
}
impl Environment {
pub fn in_class(&self, class_name: &StringName) -> Environment {
Environment { class: Some(class_name.clone()), ..self.clone() }
}
pub fn in_fun(&self, in_fun: bool) -> Environment {
Environment { in_fun, ..self.clone() }
}
pub fn is_def_mode(&self, is_def_mode: bool) -> Environment {
Environment { is_def_mode, ..self.clone() }
}
pub fn is_destruct_mode(&self, is_destruct_mode: bool) -> Self {
Environment { is_destruct_mode, ..self.clone() }
}
pub fn is_expr(&self, is_expr: bool) -> Environment {
Environment { is_expr, ..self.clone() }
}
pub fn override_mapping(&self, var: &str, mapping: usize) -> Self {
let mut var_mapping = self.var_mapping.clone();
var_mapping.insert(String::from(var), mapping);
Environment { var_mapping, ..self.clone() }
}
pub fn insert_var(&self, mutable: bool, var: &str, expect: &Expected, var_mapping: &VarMapping) -> Environment {
let expected_set = vec![(mutable, expect.clone())].into_iter().collect::<HashSet<_>>();
let mut vars = self.vars.clone();
let offset = if let Some(offset) = self.var_mapping.get(var) {
*offset + 1
} else if let Some(offset) = var_mapping.get(var) {
*offset
} else {
0_usize
};
let mut var_mappings = self.var_mapping.clone();
var_mappings.insert(String::from(var), offset);
let mapped_var = format_var_map(var, &offset);
trace!("Inserted {var} in environment: {var} => {mapped_var} ({expect})");
vars.insert(mapped_var, expected_set);
Environment { vars, var_mapping: var_mappings, ..self.clone() }
}
pub fn raises_caught(&self, raises: &HashSet<TrueName>) -> Environment {
let raises_caught = self.raises_caught.union(raises).cloned().collect();
Environment { raises_caught, ..self.clone() }
}
pub fn in_loop(&self) -> Environment {
Environment { in_loop: true, ..self.clone() }
}
pub fn return_type(&self, return_type: &Expected) -> Environment {
Environment { return_type: Some(return_type.clone()), ..self.clone() }
}
pub fn get_var(&self, var: &str, var_mapping: &VarMapping) -> Option<HashSet<(bool, Expected)>> {
let var_name = if let Some(offset) = self.var_mapping.get(var) {
format_var_map(var, offset)
} else if let Some(offset) = var_mapping.get(var) {
format_var_map(var, offset)
} else {
String::from(var)
};
self.vars.get(&var_name).cloned()
}
pub fn remove_var(&self, var: &str) -> Self {
let mut vars = self.vars.clone();
vars.remove(var);
Environment { vars, ..self.clone() }
}
pub fn with_unassigned(&self, unassigned: HashSet<String>) -> Environment {
Environment { unassigned, ..self.clone() }
}
pub fn assigned_to(&self, var: &String) -> Environment {
let mut unassigned = self.unassigned.clone();
unassigned.remove(var);
Environment { unassigned, ..self.clone() }
}
}