Add docs and an unused function for fun

This commit is contained in:
Jeff 2024-08-13 22:57:37 -04:00
parent 58780b5530
commit d32633272c
2 changed files with 43 additions and 4 deletions

View File

@ -1,15 +1,17 @@
//! Garbage-collecting context for variables. //! Garbage-collecting context for variables.
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{Arc, RwLock}, sync::{Arc, PoisonError as StdPoisonError, RwLock, RwLockWriteGuard},
}; };
use crate::{Identifier, Span, Type, Value}; use crate::{Identifier, Span, Type, Value};
pub type Variables = HashMap<Identifier, (VariableData, Span)>;
/// Garbage-collecting context for variables. /// Garbage-collecting context for variables.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Context { pub struct Context {
variables: Arc<RwLock<HashMap<Identifier, (VariableData, Span)>>>, variables: Arc<RwLock<Variables>>,
} }
impl Context { impl Context {
@ -19,24 +21,29 @@ impl Context {
} }
} }
/// Creates a deep copy of another context.
pub fn with_variables_from(other: &Self) -> Self { pub fn with_variables_from(other: &Self) -> Self {
Self { Self {
variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())), variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())),
} }
} }
/// Returns the number of variables in the context.
pub fn variable_count(&self) -> usize { pub fn variable_count(&self) -> usize {
self.variables.read().unwrap().len() self.variables.read().unwrap().len()
} }
/// Returns a boolean indicating whether the context contains the variable.
pub fn contains(&self, identifier: &Identifier) -> bool { pub fn contains(&self, identifier: &Identifier) -> bool {
self.variables.read().unwrap().contains_key(identifier) 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)> { pub fn get(&self, identifier: &Identifier) -> Option<(VariableData, Span)> {
self.variables.read().unwrap().get(identifier).cloned() 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<Type> { pub fn get_type(&self, identifier: &Identifier) -> Option<Type> {
match self.variables.read().unwrap().get(identifier) { match self.variables.read().unwrap().get(identifier) {
Some((VariableData::Type(r#type), _)) => Some(r#type.clone()), 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<VariableData> { pub fn get_variable_data(&self, identifier: &Identifier) -> Option<VariableData> {
match self.variables.read().unwrap().get(identifier) { match self.variables.read().unwrap().get(identifier) {
Some((variable_data, _)) => Some(variable_data.clone()), 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<Value> { pub fn get_value(&self, identifier: &Identifier) -> Option<Value> {
match self.variables.read().unwrap().get(identifier) { match self.variables.read().unwrap().get(identifier) {
Some((VariableData::Value(value), _)) => Some(value.clone()), 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) { pub fn set_type(&self, identifier: Identifier, r#type: Type, position: Span) {
log::trace!("Setting {identifier} to type {type} at {position:?}"); log::trace!("Setting {identifier} to type {type} at {position:?}");
@ -68,6 +78,7 @@ impl Context {
.insert(identifier, (VariableData::Type(r#type), position)); .insert(identifier, (VariableData::Type(r#type), position));
} }
/// Sets a variable to a value.
pub fn set_value(&self, identifier: Identifier, value: Value) { pub fn set_value(&self, identifier: Identifier, value: Value) {
log::trace!("Setting {identifier} to value {value}"); log::trace!("Setting {identifier} to value {value}");
@ -81,6 +92,7 @@ impl Context {
variables.insert(identifier, (VariableData::Value(value), last_position)); 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) { pub fn collect_garbage(&self, current_position: usize) {
log::trace!("Collecting garbage up to {current_position}"); log::trace!("Collecting garbage up to {current_position}");
@ -98,6 +110,8 @@ impl Context {
variables.shrink_to_fit(); 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 { pub fn update_last_position(&self, identifier: &Identifier, position: Span) -> bool {
if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) { if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) {
*last_position = position; *last_position = position;
@ -109,6 +123,23 @@ impl Context {
false 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 { impl Default for Context {
@ -123,6 +154,8 @@ pub enum VariableData {
Type(Type), Type(Type),
} }
pub type ContextPoisonError<'err> = StdPoisonError<RwLockWriteGuard<'err, Variables>>;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::vm::run_with_context; use crate::vm::run_with_context;

View File

@ -62,9 +62,15 @@ impl Identifier {
} }
} }
impl From<String> for Identifier {
fn from(string: String) -> Self {
Identifier::new(string)
}
}
impl From<&str> for Identifier { impl From<&str> for Identifier {
fn from(text: &str) -> Self { fn from(slice: &str) -> Self {
Identifier::new(text) Identifier::new(slice)
} }
} }