diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 87f4db4..37bda95 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -7,8 +7,9 @@ use serde::{de::Visitor, Deserialize, Serialize}; use crate::{ built_in_identifiers::all_built_in_identifiers, + built_in_values::all_built_in_values, error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Context, Format, SyntaxNode, Type, Value, + AbstractTree, Context, Format, SyntaxNode, Type, Value, ValueData, }; /// A string by which a variable is known to a context. @@ -60,9 +61,17 @@ impl AbstractTree for Identifier { } fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> { - if let Some(_) = context.get_type(self)? { + if let Some((_, counter)) = context.get_data_and_counter(self)? { + counter.add_allowance()?; + Ok(()) } else { + for built_in_value in all_built_in_values() { + if built_in_value.name() == self.inner().as_ref() { + return Ok(()); + } + } + Err(ValidationError::VariableIdentifierNotFound(self.clone())) } } @@ -71,18 +80,38 @@ impl AbstractTree for Identifier { if let Some(r#type) = context.get_type(self)? { Ok(r#type) } else { + for built_in_value in all_built_in_values() { + if built_in_value.name() == self.inner().as_ref() { + return Ok(built_in_value.get().r#type()?); + } + } + Err(ValidationError::VariableIdentifierNotFound(self.clone())) } } fn run(&self, _source: &str, context: &Context) -> Result { - if let Some(value) = context.get_value(self)? { - Ok(value.clone()) + if let Some((value_data, counter)) = context.get_data_and_counter(self)? { + if let ValueData::Value(value) = value_data { + counter.add_runtime_use()?; + + if counter.runtime_uses() == counter.allowances() { + context.unset(self)?; + } + + return Ok(value.clone()); + } } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::VariableIdentifierNotFound(self.clone()), - )); + for built_in_value in all_built_in_values() { + if built_in_value.name() == self.inner().as_ref() { + return Ok(built_in_value.get().clone()); + } + } } + + Err(RuntimeError::ValidationFailure( + ValidationError::VariableIdentifierNotFound(self.clone()), + )) } } diff --git a/src/context.rs b/src/context/mod.rs similarity index 65% rename from src/context.rs rename to src/context/mod.rs index f8f749c..eb9ffee 100644 --- a/src/context.rs +++ b/src/context/mod.rs @@ -27,6 +27,12 @@ //! has been explicitly set. If nothing is found, it will then check the built- //! in values and type definitions for a match. This means that the user can //! override the built-ins. +mod usage_counter; +mod value_data; + +pub use usage_counter::UsageCounter; +pub use value_data::ValueData; + use std::{ cmp::Ordering, collections::BTreeMap, @@ -45,7 +51,7 @@ use crate::{ /// See the [module-level docs][self] for more info. #[derive(Clone, Debug)] pub struct Context { - inner: Arc>>, + inner: Arc>>, } impl Context { @@ -57,7 +63,9 @@ impl Context { } /// Return a lock guard to the inner BTreeMap. - pub fn inner(&self) -> Result>, RwLockError> { + pub fn inner( + &self, + ) -> Result>, RwLockError> { Ok(self.inner.read()?) } @@ -96,21 +104,30 @@ impl Context { pub fn inherit_from(&self, other: &Context) -> Result<(), RwLockError> { let mut self_variables = self.inner.write()?; - for (identifier, value_data) in other.inner.read()?.iter() { - if let ValueData::Value { inner, .. } = value_data { - if inner.is_function() { - self_variables.insert(identifier.clone(), value_data.clone()); + for (identifier, (value_data, _counter)) in other.inner.read()?.iter() { + if let ValueData::Value(value) = value_data { + if value.is_function() { + self_variables.insert( + identifier.clone(), + (value_data.clone(), UsageCounter::new()), + ); } } - if let ValueData::TypeHint { inner } = value_data { - if inner.is_function() { - self_variables.insert(identifier.clone(), value_data.clone()); + if let ValueData::TypeHint(r#type) = value_data { + if r#type.is_function() { + self_variables.insert( + identifier.clone(), + (value_data.clone(), UsageCounter::new()), + ); } } if let ValueData::TypeDefinition(_) = value_data { - self_variables.insert(identifier.clone(), value_data.clone()); + self_variables.insert( + identifier.clone(), + (value_data.clone(), UsageCounter::new()), + ); } } @@ -139,21 +156,33 @@ impl Context { pub fn inherit_all_from(&self, other: &Context) -> Result<(), RwLockError> { let mut self_variables = self.inner.write()?; - for (identifier, value_data) in other.inner.read()?.iter() { - self_variables.insert(identifier.clone(), value_data.clone()); + for (identifier, (value_data, _counter)) in other.inner.read()?.iter() { + self_variables.insert( + identifier.clone(), + (value_data.clone(), UsageCounter::new()), + ); } Ok(()) } - /// Get a value from the context. - /// - /// This will also return a built-in value if one matches the key. See the - /// [module-level docs][self] for more info. + /// Get a [Value] and its [UsageCounter] from the context. + pub fn get_data_and_counter( + &self, + identifier: &Identifier, + ) -> Result, RwLockError> { + if let Some((value_data, counter)) = self.inner.read()?.get(identifier) { + return Ok(Some((value_data.clone(), counter.clone()))); + } + + Ok(None) + } + + /// Get a [Value] from the context. pub fn get_value(&self, identifier: &Identifier) -> Result, RwLockError> { - if let Some(value_data) = self.inner.read()?.get(identifier) { - if let ValueData::Value { inner, .. } = value_data { - return Ok(Some(inner.clone())); + if let Some((value_data, _counter)) = self.inner.read()?.get(identifier) { + if let ValueData::Value(value) = value_data { + return Ok(Some(value.clone())); } } @@ -166,15 +195,15 @@ impl Context { Ok(None) } - /// Get a type from the context. + /// Get a [Type] from the context. /// - /// If the key matches a stored value, its type will be returned. It if + /// If the key matches a stored [Value], its type will be returned. It if /// matches a type hint, the type hint will be returned. pub fn get_type(&self, identifier: &Identifier) -> Result, RwLockError> { - if let Some(value_data) = self.inner.read()?.get(identifier) { + if let Some((value_data, _counter)) = self.inner.read()?.get(identifier) { match value_data { - ValueData::Value { inner, .. } => return Ok(Some(inner.r#type()?)), - ValueData::TypeHint { inner, .. } => return Ok(Some(inner.clone())), + ValueData::Value(value) => return Ok(Some(value.r#type()?)), + ValueData::TypeHint(r#type) => return Ok(Some(r#type.clone())), ValueData::TypeDefinition(_) => todo!(), } } @@ -188,7 +217,7 @@ impl Context { Ok(None) } - /// Get a type definition from the context. + /// Get a [TypeDefinition] from the context. /// /// This will also return a built-in type definition if one matches the key. /// See the [module-level docs][self] for more info. @@ -196,7 +225,7 @@ impl Context { &self, identifier: &Identifier, ) -> Result, RwLockError> { - if let Some(value_data) = self.inner.read()?.get(identifier) { + if let Some((value_data, _counter)) = self.inner.read()?.get(identifier) { if let ValueData::TypeDefinition(definition) = value_data { return Ok(Some(definition.clone())); } @@ -215,13 +244,14 @@ impl Context { pub fn set_value(&self, key: Identifier, value: Value) -> Result<(), RwLockError> { log::info!("Setting value: {key} = {value}"); - self.inner.write()?.insert( - key, - ValueData::Value { - inner: value, - runtime_uses: Arc::new(RwLock::new(0)), - }, - ); + let mut map = self.inner.write()?; + let old_data = map.remove(&key); + + if let Some((_, old_counter)) = old_data { + map.insert(key, (ValueData::Value(value), old_counter.clone())); + } else { + map.insert(key, (ValueData::Value(value), UsageCounter::new())); + } Ok(()) } @@ -235,7 +265,7 @@ impl Context { self.inner .write()? - .insert(key, ValueData::TypeHint { inner: r#type }); + .insert(key, (ValueData::TypeHint(r#type), UsageCounter::new())); Ok(()) } @@ -249,15 +279,18 @@ impl Context { key: Identifier, definition: TypeDefinition, ) -> Result<(), RwLockError> { - self.inner - .write()? - .insert(key, ValueData::TypeDefinition(definition)); + self.inner.write()?.insert( + key, + (ValueData::TypeDefinition(definition), UsageCounter::new()), + ); Ok(()) } /// Remove a key-value pair. pub fn unset(&self, key: &Identifier) -> Result<(), RwLockError> { + log::debug!("Dropping variable {key}."); + self.inner.write()?.remove(key); Ok(()) @@ -294,7 +327,7 @@ impl PartialEq for Context { } impl PartialOrd for Context { - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } @@ -308,79 +341,6 @@ impl Ord for Context { } } -#[derive(Clone, Debug)] -pub enum ValueData { - Value { - inner: Value, - runtime_uses: Arc>, - }, - TypeHint { - inner: Type, - }, - TypeDefinition(TypeDefinition), -} - -impl Eq for ValueData {} - -impl PartialEq for ValueData { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - ValueData::Value { - inner: left_inner, - runtime_uses: left_runtime_uses, - }, - ValueData::Value { - inner: right_inner, - runtime_uses: right_runtime_uses, - }, - ) => { - if left_inner != right_inner { - return false; - } else { - *left_runtime_uses.read().unwrap() == *right_runtime_uses.read().unwrap() - } - } - ( - ValueData::TypeHint { inner: left_inner }, - ValueData::TypeHint { inner: right_inner }, - ) => left_inner == right_inner, - _ => false, - } - } -} - -impl PartialOrd for ValueData { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ValueData { - fn cmp(&self, other: &Self) -> Ordering { - use Ordering::*; - - match (self, other) { - ( - ValueData::Value { - inner: inner_left, .. - }, - ValueData::Value { - inner: inner_right, .. - }, - ) => inner_left.cmp(inner_right), - (ValueData::Value { .. }, _) => Greater, - ( - ValueData::TypeHint { inner: inner_left }, - ValueData::TypeHint { inner: inner_right }, - ) => inner_left.cmp(inner_right), - (ValueData::TypeDefinition(left), ValueData::TypeDefinition(right)) => left.cmp(right), - (ValueData::TypeDefinition(_), _) => Greater, - (ValueData::TypeHint { .. }, _) => Less, - } - } -} - impl Display for Context { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "{{")?; diff --git a/src/context/usage_counter.rs b/src/context/usage_counter.rs new file mode 100644 index 0000000..624eb29 --- /dev/null +++ b/src/context/usage_counter.rs @@ -0,0 +1,70 @@ +use std::{ + cmp::Ordering, + sync::{Arc, RwLock}, +}; + +use crate::error::rw_lock_error::RwLockError; + +#[derive(Clone, Debug)] +pub struct UsageCounter(Arc>); + +impl UsageCounter { + pub fn new() -> UsageCounter { + UsageCounter(Arc::new(RwLock::new(UsageCounterInner { + allowances: 0, + runtime_uses: 0, + }))) + } + + pub fn allowances(&self) -> Result { + Ok(self.0.read()?.allowances) + } + + pub fn runtime_uses(&self) -> Result { + Ok(self.0.read()?.runtime_uses) + } + + pub fn add_allowance(&self) -> Result<(), RwLockError> { + self.0.write()?.allowances += 1; + + Ok(()) + } + + pub fn add_runtime_use(&self) -> Result<(), RwLockError> { + self.0.write()?.runtime_uses += 1; + + Ok(()) + } +} + +impl Eq for UsageCounter {} + +impl PartialEq for UsageCounter { + fn eq(&self, other: &Self) -> bool { + let left = self.0.read().unwrap(); + let right = other.0.read().unwrap(); + + *left == *right + } +} + +impl PartialOrd for UsageCounter { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for UsageCounter { + fn cmp(&self, other: &Self) -> Ordering { + let left = self.0.read().unwrap(); + let right = other.0.read().unwrap(); + + left.cmp(&right) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +struct UsageCounterInner { + pub allowances: usize, + pub runtime_uses: usize, +} diff --git a/src/context/value_data.rs b/src/context/value_data.rs new file mode 100644 index 0000000..90e3cbf --- /dev/null +++ b/src/context/value_data.rs @@ -0,0 +1,8 @@ +use crate::{Type, TypeDefinition, Value}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum ValueData { + Value(Value), + TypeHint(Type), + TypeDefinition(TypeDefinition), +} diff --git a/src/main.rs b/src/main.rs index c824846..3d1a4b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -308,10 +308,10 @@ impl Completer for DustCompleter { } } - for (key, value_data) in self.context.inner().unwrap().iter() { + for (key, (value_data, _counter)) in self.context.inner().unwrap().iter() { let value = match value_data { - ValueData::Value { inner, .. } => inner, - ValueData::TypeHint { .. } => continue, + ValueData::Value(value) => value, + ValueData::TypeHint(_) => continue, ValueData::TypeDefinition(_) => continue, };