Add docs and an unused function for fun
This commit is contained in:
parent
58780b5530
commit
d32633272c
@ -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<Identifier, (VariableData, Span)>;
|
||||
|
||||
/// Garbage-collecting context for variables.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Context {
|
||||
variables: Arc<RwLock<HashMap<Identifier, (VariableData, Span)>>>,
|
||||
variables: Arc<RwLock<Variables>>,
|
||||
}
|
||||
|
||||
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<Type> {
|
||||
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<VariableData> {
|
||||
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<Value> {
|
||||
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<RwLockWriteGuard<'err, Variables>>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vm::run_with_context;
|
||||
|
@ -62,9 +62,15 @@ impl Identifier {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user