diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index cf7655d..137c395 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -1,15 +1,17 @@ //! Garbage-collecting context for variables. use std::{ collections::HashMap, - sync::{Arc, RwLock}, + sync::{Arc, PoisonError as StdPoisonError, RwLock, RwLockWriteGuard}, }; use crate::{Identifier, Span, Type, Value}; +pub type Variables = HashMap; + /// Garbage-collecting context for variables. #[derive(Debug, Clone)] pub struct Context { - variables: Arc>>, + variables: Arc>, } impl Context { @@ -19,24 +21,29 @@ impl Context { } } + /// Creates a deep copy of another context. pub fn with_variables_from(other: &Self) -> Self { Self { variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())), } } + /// Returns the number of variables in the context. pub fn variable_count(&self) -> usize { self.variables.read().unwrap().len() } + /// Returns a boolean indicating whether the context contains the variable. pub fn contains(&self, identifier: &Identifier) -> bool { self.variables.read().unwrap().contains_key(identifier) } + /// Returns the full VariableData and Span if the context contains the given identifier. pub fn get(&self, identifier: &Identifier) -> Option<(VariableData, Span)> { self.variables.read().unwrap().get(identifier).cloned() } + /// Returns the type of the variable with the given identifier. pub fn get_type(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { Some((VariableData::Type(r#type), _)) => Some(r#type.clone()), @@ -45,6 +52,7 @@ impl Context { } } + /// Returns the VariableData of the variable with the given identifier. pub fn get_variable_data(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { Some((variable_data, _)) => Some(variable_data.clone()), @@ -52,6 +60,7 @@ impl Context { } } + /// Returns the value of the variable with the given identifier. pub fn get_value(&self, identifier: &Identifier) -> Option { match self.variables.read().unwrap().get(identifier) { Some((VariableData::Value(value), _)) => Some(value.clone()), @@ -59,6 +68,7 @@ impl Context { } } + /// Sets a variable to a type, with a position given for garbage collection. pub fn set_type(&self, identifier: Identifier, r#type: Type, position: Span) { log::trace!("Setting {identifier} to type {type} at {position:?}"); @@ -68,6 +78,7 @@ impl Context { .insert(identifier, (VariableData::Type(r#type), position)); } + /// Sets a variable to a value. pub fn set_value(&self, identifier: Identifier, value: Value) { log::trace!("Setting {identifier} to value {value}"); @@ -81,6 +92,7 @@ impl Context { variables.insert(identifier, (VariableData::Value(value), last_position)); } + /// Collects garbage up to the given position, removing all variables with lesser positions. pub fn collect_garbage(&self, current_position: usize) { log::trace!("Collecting garbage up to {current_position}"); @@ -98,6 +110,8 @@ impl Context { variables.shrink_to_fit(); } + /// Updates a variable's last known position, allowing it to live longer in the program. + /// Returns a boolean indicating whether the variable was found. pub fn update_last_position(&self, identifier: &Identifier, position: Span) -> bool { if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) { *last_position = position; @@ -109,6 +123,23 @@ impl Context { false } } + + /// Recovers the context from a poisoned state by recovering data from an error. + /// + /// This method is not used. The context's other methods do not return poison errors because + /// they are infallible. + pub fn _recover_from_poison(&mut self, error: &ContextPoisonError) { + log::debug!("Context is recovering from poison error"); + + let recovered = error.get_ref(); + let mut new_variables = HashMap::new(); + + for (identifier, (variable_data, position)) in recovered.iter() { + new_variables.insert(identifier.clone(), (variable_data.clone(), *position)); + } + + self.variables = Arc::new(RwLock::new(new_variables)); + } } impl Default for Context { @@ -123,6 +154,8 @@ pub enum VariableData { Type(Type), } +pub type ContextPoisonError<'err> = StdPoisonError>; + #[cfg(test)] mod tests { use crate::vm::run_with_context; diff --git a/dust-lang/src/identifier.rs b/dust-lang/src/identifier.rs index 5bb8988..c35d41a 100644 --- a/dust-lang/src/identifier.rs +++ b/dust-lang/src/identifier.rs @@ -62,9 +62,15 @@ impl Identifier { } } +impl From for Identifier { + fn from(string: String) -> Self { + Identifier::new(string) + } +} + impl From<&str> for Identifier { - fn from(text: &str) -> Self { - Identifier::new(text) + fn from(slice: &str) -> Self { + Identifier::new(slice) } }