use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use serde_json::Value;
use crate::ast::{AstNode, AstError};
pub type Functor = fn(&Rc<RefCell<Env>>, &[Value]) -> Result<Value, AstError>;
pub struct Env {
parent: Option<Rc<RefCell<Env>>>,
bindings: HashMap<String, Value>,
functor_map: HashMap<String, Functor>,
current_meta: HashMap<String, Value>,
}
impl Env {
fn as_rc(&self) -> Rc<RefCell<Env>> {
if let Some(parent) = &self.parent {
Rc::clone(parent)
} else {
Rc::new(RefCell::new(self.clone()))
}
}
pub fn new() -> Self {
Self {
parent: None,
bindings: HashMap::new(),
functor_map: HashMap::new(),
current_meta: HashMap::new(),
}
}
pub fn new_with_parent(parent: Option<Rc<RefCell<Env>>>) -> Self {
Self {
parent,
bindings: HashMap::new(),
functor_map: HashMap::new(),
current_meta: HashMap::new(),
}
}
pub fn get_parent(&self) -> Option<Rc<RefCell<Env>>> {
self.parent.as_ref().map(Rc::clone)
}
pub fn get_meta(&self) -> &HashMap<String, Value> {
&self.current_meta
}
pub fn set_meta(&mut self, meta: HashMap<String, Value>) {
self.current_meta = meta;
}
pub fn clear_meta(&mut self) {
self.current_meta.clear();
}
pub fn resolve(&self, symbol: &str) -> Option<Value> {
if let Some(value) = self.bindings.get(symbol) {
Some(value.clone())
} else if let Some(parent) = &self.parent {
parent.borrow().resolve(symbol)
} else {
None
}
}
pub fn register(&mut self, name: String, value: Value) -> Result<(), AstError> {
if self.bindings.contains_key(&name) {
return Err(AstError::EvalError(
format!("Symbol '{}' already exists in current scope", name)
));
}
self.bindings.insert(name, value);
Ok(())
}
pub fn set(&mut self, name: String, value: Value) {
self.bindings.insert(name, value);
}
pub fn exists(&self, name: &str) -> bool {
self.bindings.contains_key(name) ||
self.parent.as_ref().map_or(false, |p| p.borrow().exists(name))
}
pub fn register_functor(&mut self, name: String, functor: Functor) {
self.functor_map.insert(name, functor);
}
pub fn load(&mut self, module: &HashMap<&'static str, Functor>) {
for (name, functor) in module {
self.functor_map.insert(name.to_string(), *functor);
}
}
pub fn eval(&self, node: &dyn AstNode, env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
node.apply(env)
}
pub fn eval_node(&self, node: &dyn AstNode) -> Result<Value, AstError> {
let env = self.as_rc();
node.apply(&env)
}
pub fn apply_functor(
&self,
name: &str,
env: &Rc<RefCell<Env>>,
args: &[&dyn AstNode]
) -> Result<Value, AstError> {
let functor = self.resolve_functor(name)
.ok_or_else(|| AstError::SymbolNotFound(name.to_string()))?;
let json_args: Vec<Value> = args.iter()
.map(|node| node.to_json())
.collect();
functor(env, &json_args)
}
pub fn apply_functor_node(&self, name: &str, args: &[&dyn AstNode]) -> Result<Value, AstError> {
let env = self.as_rc();
let functor = self.resolve_functor(name)
.ok_or_else(|| AstError::SymbolNotFound(name.to_string()))?;
let json_args: Vec<Value> = args.iter()
.map(|node| node.to_json())
.collect();
functor(&env, &json_args)
}
pub fn apply_functor_with_values(
&self,
name: &str,
env: &Rc<RefCell<Env>>,
args: &[Value]
) -> Result<Value, AstError> {
let functor = self.resolve_functor(name)
.ok_or_else(|| AstError::SymbolNotFound(name.to_string()))?;
functor(env, args)
}
pub fn apply_functor_values(&self, name: &str, args: &[Value]) -> Result<Value, AstError> {
let env = self.as_rc();
let functor = self.resolve_functor(name)
.ok_or_else(|| AstError::SymbolNotFound(name.to_string()))?;
functor(&env, args)
}
pub fn resolve_functor(&self, name: &str) -> Option<Functor> {
if let Some(&functor) = self.functor_map.get(name) {
Some(functor)
} else if let Some(parent) = &self.parent {
parent.borrow().resolve_functor(name)
} else {
None
}
}
}
impl Clone for Env {
fn clone(&self) -> Self {
Self {
parent: self.parent.as_ref().map(Rc::clone),
bindings: self.bindings.clone(),
functor_map: self.functor_map.clone(),
current_meta: self.current_meta.clone(),
}
}
}
impl Default for Env {
fn default() -> Self {
Self::new()
}
}