use crate::eval::{Value, Environment};
use crate::diagnostics::{Error, Result};
use std::collections::HashMap;
use std::rc::Rc;
use std::time::SystemTime;
#[derive(Debug)]
pub struct EnvironmentManipulator {
environments: HashMap<String, EnvironmentHandle>,
hierarchy: super::environment_hierarchy::EnvironmentHierarchy,
snapshots: HashMap<String, super::environment_tracking::EnvironmentSnapshot>,
change_tracker: super::environment_tracking::ChangeTracker,
}
#[derive(Debug, Clone)]
pub struct EnvironmentHandle {
pub environment: Rc<Environment>,
pub metadata: EnvironmentMetadata,
pub created_at: SystemTime,
pub last_accessed: SystemTime,
}
#[derive(Debug, Clone)]
pub struct EnvironmentMetadata {
pub name: String,
pub env_type: EnvironmentType,
pub parent: Option<String>,
pub children: Vec<String>,
pub tags: Vec<String>,
pub properties: HashMap<String, Value>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum EnvironmentType {
Global,
Module,
Function,
Local,
Macro,
Sandbox,
Repl,
Custom(String),
}
impl EnvironmentManipulator {
pub fn install_primitives(&self, _env: &Rc<Environment>) -> Result<()> {
Ok(())
}
pub fn new() -> Self {
Self {
environments: HashMap::new(),
hierarchy: super::environment_hierarchy::EnvironmentHierarchy::new(),
snapshots: HashMap::new(),
change_tracker: super::environment_tracking::ChangeTracker::new(1000),
}
}
pub fn register_environment(
&mut self,
name: String,
environment: Rc<Environment>,
env_type: EnvironmentType,
) -> Result<()> {
let metadata = EnvironmentMetadata {
name: name.clone(),
env_type,
parent: None,
children: Vec::new(),
tags: Vec::new(),
properties: HashMap::new(),
};
let handle = EnvironmentHandle {
environment,
metadata,
created_at: SystemTime::now(),
last_accessed: SystemTime::now(),
};
self.environments.insert(name.clone(), handle);
self.hierarchy.add_root(name.clone());
self.change_tracker.track_change(name, super::environment_tracking::EnvironmentChange {
change_type: super::environment_tracking::ChangeType::Create,
variable: "".to_string(),
old_value: None,
new_value: None,
timestamp: SystemTime::now(),
});
Ok(())
}
pub fn create_child_environment(
&mut self,
parent_name: &str,
child_name: String,
env_type: EnvironmentType,
) -> Result<Rc<Environment>> {
let parent_env = self.get_environment(parent_name)?;
let child_env = Rc::new(Environment::new(Some(parent_env.clone()), 0));
let metadata = EnvironmentMetadata {
name: child_name.clone(),
env_type,
parent: Some(parent_name.to_string()),
children: Vec::new(),
tags: Vec::new(),
properties: HashMap::new(),
};
if let Some(parent_handle) = self.environments.get_mut(parent_name) {
parent_handle.metadata.children.push(child_name.clone());
}
let handle = EnvironmentHandle {
environment: child_env.clone(),
metadata,
created_at: SystemTime::now(),
last_accessed: SystemTime::now(),
};
self.environments.insert(child_name.clone(), handle);
self.hierarchy.add_child(parent_name.to_string(), child_name.clone());
Ok(child_env)
}
pub fn get_environment(&mut self, name: &str) -> Result<Rc<Environment>> {
let handle = self.environments.get_mut(name)
.ok_or_else(|| Error::runtime_error(
format!("Environment '{name}' not found"),
None,
))?;
handle.last_accessed = SystemTime::now();
Ok(handle.environment.clone())
}
pub fn get_metadata(&self, name: &str) -> Option<&EnvironmentMetadata> {
self.environments.get(name).map(|h| &h.metadata)
}
pub fn create_snapshot(&mut self, env_name: &str, snapshot_id: String) -> Result<()> {
let env = self.get_environment(env_name)?;
let bindings = env.get_all_bindings();
let snapshot = super::environment_tracking::EnvironmentSnapshot {
id: snapshot_id.clone(),
environment_name: env_name.to_string(),
bindings,
timestamp: SystemTime::now(),
metadata: HashMap::new(),
};
self.snapshots.insert(snapshot_id, snapshot);
Ok(())
}
pub fn restore_from_snapshot(&mut self, snapshot_id: &str) -> Result<()> {
let snapshot = self.snapshots.get(snapshot_id)
.ok_or_else(|| Error::runtime_error(
format!("Snapshot '{snapshot_id}' not found"),
None,
))?
.clone();
let env = self.get_environment(&snapshot.environment_name)?;
env.clear_all_bindings();
for (name, value) in snapshot.bindings {
env.define(name, value);
}
Ok(())
}
pub fn get_changes(&self, env_name: &str) -> Vec<&super::environment_tracking::EnvironmentChange> {
self.change_tracker.changes.get(env_name)
.map(|changes| changes.iter().collect())
.unwrap_or_default()
}
pub fn remove_environment(&mut self, name: &str) -> Result<()> {
if let Some(_handle) = self.environments.remove(name) {
self.hierarchy.remove_node(name);
self.change_tracker.track_change(name.to_string(), super::environment_tracking::EnvironmentChange {
change_type: super::environment_tracking::ChangeType::Destroy,
variable: "".to_string(),
old_value: None,
new_value: None,
timestamp: SystemTime::now(),
});
Ok(())
} else {
Err(Box::new(Error::runtime_error(
format!("Environment '{name}' not found"),
None,
)))
}
}
}
pub trait EnvironmentExt {
fn clear_all_bindings(&self);
fn get_all_bindings(&self) -> HashMap<String, Value>;
}
impl EnvironmentExt for Environment {
fn clear_all_bindings(&self) {
}
fn get_all_bindings(&self) -> HashMap<String, Value> {
HashMap::new()
}
}
impl Default for EnvironmentManipulator {
fn default() -> Self {
Self::new()
}
}