use crate::{
parser::Element, EpsilonChecker, HostFunction, HostFunctionBinding, HostType, TokenTransformer,
TypeChecker, WanderValue,
};
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
pub struct Environment<T: HostType> {
token_transformers: RefCell<HashMap<String, Rc<TokenTransformer>>>,
host_functions: RefCell<HashMap<String, Rc<dyn HostFunction<T>>>>,
scopes: Vec<HashMap<String, WanderValue<T>>>,
type_checker: Box<dyn TypeChecker<T>>,
}
impl<T: HostType> Environment<T> {
pub fn new() -> Environment<T> {
Environment {
token_transformers: RefCell::new(HashMap::new()),
host_functions: RefCell::new(HashMap::new()),
scopes: vec![HashMap::new()],
type_checker: Box::new(EpsilonChecker {}),
}
}
pub fn add_scope(&mut self) {
self.scopes.push(HashMap::new());
}
pub fn remove_scope(&mut self) {
self.scopes.pop();
}
pub fn read(&self, name: &String) -> Option<WanderValue<T>> {
let mut index = self.scopes.len();
while index > 0 {
match self.scopes.get(index - 1) {
Some(scope) => {
if let Some(value) = scope.get(name) {
return Some(value.clone());
}
}
_ => return None,
}
index -= 1;
}
None
}
pub fn bind(&mut self, name: String, value: WanderValue<T>) {
let mut current_scope = self.scopes.pop().unwrap();
current_scope.insert(name, value);
self.scopes.push(current_scope);
}
pub fn bind_host_function(&mut self, function: Rc<dyn HostFunction<T>>) {
let full_name = function.binding().name.to_string();
self.host_functions
.borrow_mut()
.insert(full_name.clone(), function.clone());
let mut parameters = function.binding().parameters.clone();
let mut result = None;
parameters.reverse();
parameters.iter().for_each(|(name, tag)| match &result {
Some(value) => match value {
WanderValue::Lambda(innerp, i, o, b) => {
let p = parameters.clone();
result = Some(WanderValue::Lambda(
name.clone(),
tag.clone(),
None,
Box::new(Element::Lambda(
innerp.clone(),
i.clone(),
o.clone(),
b.clone(),
)),
));
}
_ => panic!("Should never reach."),
},
None => {
let p = parameters.clone();
result = Some(WanderValue::Lambda(
name.clone(),
tag.clone(),
None,
Box::new(Element::HostFunction(full_name.clone())),
));
}
});
self.bind(full_name, result.unwrap());
}
pub fn read_host_function(&self, name: &String) -> Option<Rc<dyn HostFunction<T>>> {
match self.host_functions.borrow().get(name) {
None => None,
Some(value) => Some(value.clone()),
}
}
pub fn bind_token_transformer(
&mut self,
module: String,
name: String,
transformer: Rc<TokenTransformer>,
) {
let full_name = format!("{module}.{name}");
self.token_transformers
.borrow_mut()
.insert(full_name, transformer);
}
pub fn read_token_transformer(&self, name: &String) -> Option<Rc<TokenTransformer>> {
self.token_transformers.borrow().get(name).cloned()
}
pub fn bound_names(&self) -> HashSet<String> {
let mut names = HashSet::new();
for native_function in self.host_functions.borrow().keys() {
names.insert(native_function.clone());
}
for scope in self.scopes.iter() {
for name in scope.keys() {
names.insert(name.clone());
}
}
names
}
pub fn environment(&self) -> Vec<HostFunctionBinding> {
todo!()
}
}