2024-02-25 18:49:26 +00:00
|
|
|
use std::{
|
2024-06-17 21:39:44 +00:00
|
|
|
collections::HashMap,
|
2024-03-23 15:24:25 +00:00
|
|
|
sync::{Arc, RwLock, RwLockReadGuard},
|
2024-02-25 18:49:26 +00:00
|
|
|
};
|
|
|
|
|
2024-03-06 23:15:25 +00:00
|
|
|
use crate::{
|
2024-03-25 04:16:55 +00:00
|
|
|
abstract_tree::Type,
|
2024-03-19 22:31:52 +00:00
|
|
|
error::{RwLockPoisonError, ValidationError},
|
2024-03-25 04:16:55 +00:00
|
|
|
identifier::Identifier,
|
2024-03-24 00:36:23 +00:00
|
|
|
Value,
|
2024-03-06 23:15:25 +00:00
|
|
|
};
|
2024-02-25 18:49:26 +00:00
|
|
|
|
2024-03-12 01:57:27 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-05-21 20:29:54 +00:00
|
|
|
pub struct Context<'a> {
|
2024-06-17 21:39:44 +00:00
|
|
|
variables: Arc<RwLock<HashMap<Identifier, (VariableData, UsageData)>>>,
|
2024-05-21 20:29:54 +00:00
|
|
|
parent: Option<&'a Context<'a>>,
|
|
|
|
is_clean: Arc<RwLock<bool>>,
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 20:29:54 +00:00
|
|
|
impl<'a> Context<'a> {
|
|
|
|
pub fn new(parent: Option<&'a Context>) -> Self {
|
2024-02-25 18:49:26 +00:00
|
|
|
Self {
|
2024-06-17 21:39:44 +00:00
|
|
|
variables: Arc::new(RwLock::new(HashMap::new())),
|
2024-05-21 20:29:54 +00:00
|
|
|
parent,
|
|
|
|
is_clean: Arc::new(RwLock::new(true)),
|
2024-03-06 23:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-17 21:38:24 +00:00
|
|
|
pub fn create_child<'b>(&'b self) -> Context<'b> {
|
|
|
|
Context::new(Some(self))
|
|
|
|
}
|
|
|
|
|
2024-03-20 08:42:13 +00:00
|
|
|
pub fn inner(
|
|
|
|
&self,
|
2024-06-17 21:39:44 +00:00
|
|
|
) -> Result<RwLockReadGuard<HashMap<Identifier, (VariableData, UsageData)>>, RwLockPoisonError>
|
2024-04-22 05:51:34 +00:00
|
|
|
{
|
2024-04-22 07:41:21 +00:00
|
|
|
Ok(self.variables.read()?)
|
2024-03-20 08:42:13 +00:00
|
|
|
}
|
|
|
|
|
2024-03-17 17:36:31 +00:00
|
|
|
pub fn contains(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
|
2024-04-22 07:41:21 +00:00
|
|
|
log::trace!("Checking that {identifier} exists.");
|
|
|
|
|
2024-05-21 20:29:54 +00:00
|
|
|
if self.variables.read()?.contains_key(identifier) {
|
|
|
|
Ok(true)
|
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.contains(identifier)
|
|
|
|
} else {
|
|
|
|
Ok(false)
|
|
|
|
}
|
2024-03-12 01:57:27 +00:00
|
|
|
}
|
|
|
|
|
2024-03-19 22:31:52 +00:00
|
|
|
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
|
2024-06-18 22:54:17 +00:00
|
|
|
if let Some((data, _)) = self.variables.read()?.get(identifier) {
|
2024-04-27 07:40:05 +00:00
|
|
|
log::trace!("Getting {identifier}'s type.");
|
2024-04-22 05:51:34 +00:00
|
|
|
|
2024-06-18 22:54:17 +00:00
|
|
|
let r#type = match data {
|
2024-06-17 14:10:06 +00:00
|
|
|
VariableData::Type(r#type) => r#type.clone(),
|
|
|
|
VariableData::Value(value) => value.r#type(self)?,
|
2024-03-12 01:57:27 +00:00
|
|
|
};
|
|
|
|
|
2024-03-23 12:15:48 +00:00
|
|
|
Ok(Some(r#type.clone()))
|
2024-05-21 20:29:54 +00:00
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.get_type(identifier)
|
2024-03-23 12:15:48 +00:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
2024-03-18 12:15:30 +00:00
|
|
|
}
|
2024-03-06 23:15:25 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 20:29:54 +00:00
|
|
|
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
2024-06-17 14:10:06 +00:00
|
|
|
if let Some((VariableData::Value(value), usage_data)) =
|
|
|
|
self.variables.read()?.get(identifier)
|
2024-04-22 05:51:34 +00:00
|
|
|
{
|
|
|
|
log::trace!("Using {identifier}'s value.");
|
|
|
|
|
2024-04-22 09:50:26 +00:00
|
|
|
usage_data.inner().write()?.actual += 1;
|
2024-05-21 20:29:54 +00:00
|
|
|
*self.is_clean.write()? = false;
|
2024-04-22 05:51:34 +00:00
|
|
|
|
2024-03-17 17:36:31 +00:00
|
|
|
Ok(Some(value.clone()))
|
2024-05-21 20:29:54 +00:00
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.use_value(identifier)
|
2024-03-12 01:57:27 +00:00
|
|
|
} else {
|
2024-03-18 12:15:30 +00:00
|
|
|
Ok(None)
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 11:56:03 +00:00
|
|
|
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
2024-06-17 14:10:06 +00:00
|
|
|
if let Some((VariableData::Value(value), _)) = self.variables.read()?.get(identifier) {
|
2024-04-22 11:56:03 +00:00
|
|
|
log::trace!("Getting {identifier}'s value.");
|
|
|
|
|
|
|
|
Ok(Some(value.clone()))
|
2024-05-21 20:29:54 +00:00
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.get_value(identifier)
|
2024-04-22 11:56:03 +00:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-04-27 07:40:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_data(
|
|
|
|
&self,
|
|
|
|
identifier: &Identifier,
|
2024-06-17 14:10:06 +00:00
|
|
|
) -> Result<Option<(VariableData, UsageData)>, RwLockPoisonError> {
|
2024-04-27 07:40:05 +00:00
|
|
|
if let Some(full_data) = self.variables.read()?.get(identifier) {
|
|
|
|
log::trace!("Getting {identifier}'s value.");
|
|
|
|
|
|
|
|
Ok(Some(full_data.clone()))
|
2024-05-21 20:29:54 +00:00
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.get_data(identifier)
|
2024-04-27 07:40:05 +00:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-04-22 11:56:03 +00:00
|
|
|
}
|
|
|
|
|
2024-03-06 23:15:25 +00:00
|
|
|
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> {
|
2024-04-22 07:41:21 +00:00
|
|
|
log::debug!("Setting {identifier} to type {}.", r#type);
|
2024-04-22 05:51:34 +00:00
|
|
|
|
2024-04-22 07:41:21 +00:00
|
|
|
self.variables
|
2024-03-06 23:15:25 +00:00
|
|
|
.write()?
|
2024-06-17 14:10:06 +00:00
|
|
|
.insert(identifier, (VariableData::Type(r#type), UsageData::new()));
|
2024-02-25 18:49:26 +00:00
|
|
|
|
2024-03-06 23:15:25 +00:00
|
|
|
Ok(())
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
|
|
|
|
2024-04-22 12:25:20 +00:00
|
|
|
pub fn set_value(
|
|
|
|
&mut self,
|
|
|
|
identifier: Identifier,
|
|
|
|
value: Value,
|
|
|
|
) -> Result<(), RwLockPoisonError> {
|
2024-04-22 07:41:21 +00:00
|
|
|
log::debug!("Setting {identifier} to value {value}.");
|
2024-04-22 05:51:34 +00:00
|
|
|
|
2024-04-22 07:41:21 +00:00
|
|
|
let mut variables = self.variables.write()?;
|
|
|
|
let old_usage_data = variables
|
|
|
|
.remove(&identifier)
|
|
|
|
.map(|(_, usage_data)| usage_data);
|
2024-04-22 05:51:34 +00:00
|
|
|
|
|
|
|
if let Some(usage_data) = old_usage_data {
|
2024-06-17 14:10:06 +00:00
|
|
|
variables.insert(identifier, (VariableData::Value(value), usage_data));
|
2024-04-22 05:51:34 +00:00
|
|
|
} else {
|
2024-06-17 14:10:06 +00:00
|
|
|
variables.insert(identifier, (VariableData::Value(value), UsageData::new()));
|
2024-04-22 05:51:34 +00:00
|
|
|
}
|
2024-02-25 18:49:26 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-03-23 12:47:57 +00:00
|
|
|
|
2024-04-22 05:51:34 +00:00
|
|
|
pub fn clean(&mut self) -> Result<(), RwLockPoisonError> {
|
2024-05-21 20:29:54 +00:00
|
|
|
if *self.is_clean.read()? {
|
2024-04-22 11:56:03 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2024-04-22 07:41:21 +00:00
|
|
|
self.variables
|
2024-04-22 05:51:34 +00:00
|
|
|
.write()?
|
2024-04-22 11:56:03 +00:00
|
|
|
.retain(|identifier, (value_data, usage_data)| {
|
2024-06-17 14:10:06 +00:00
|
|
|
if let VariableData::Value(_) = value_data {
|
2024-04-22 11:56:03 +00:00
|
|
|
let usage = usage_data.inner().read().unwrap();
|
2024-04-22 09:50:26 +00:00
|
|
|
|
2024-04-22 11:56:03 +00:00
|
|
|
if usage.actual < usage.expected {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
log::trace!("Removing variable {identifier}.");
|
2024-04-22 05:51:34 +00:00
|
|
|
|
2024-04-22 11:56:03 +00:00
|
|
|
false
|
|
|
|
}
|
|
|
|
} else {
|
2024-04-22 05:51:34 +00:00
|
|
|
false
|
|
|
|
}
|
2024-04-22 07:41:21 +00:00
|
|
|
});
|
2024-04-22 05:51:34 +00:00
|
|
|
|
2024-05-21 20:29:54 +00:00
|
|
|
*self.is_clean.write()? = true;
|
2024-04-22 11:56:03 +00:00
|
|
|
|
2024-04-22 05:51:34 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-22 12:25:20 +00:00
|
|
|
pub fn is_clean(&mut self) -> Result<bool, RwLockPoisonError> {
|
2024-05-21 20:29:54 +00:00
|
|
|
if *self.is_clean.read()? {
|
2024-04-22 12:25:20 +00:00
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
for (_, (_, usage_data)) in self.variables.read()?.iter() {
|
|
|
|
let usage_data = usage_data.inner().read().unwrap();
|
|
|
|
|
|
|
|
if usage_data.actual > usage_data.expected {
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 05:51:34 +00:00
|
|
|
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
|
2024-04-22 09:50:26 +00:00
|
|
|
if let Some((_, usage_data)) = self.variables.read()?.get(identifier) {
|
2024-04-22 05:51:34 +00:00
|
|
|
log::trace!("Adding expected use for variable {identifier}.");
|
|
|
|
|
2024-04-22 09:50:26 +00:00
|
|
|
usage_data.inner().write()?.expected += 1;
|
2024-04-22 05:51:34 +00:00
|
|
|
|
|
|
|
Ok(true)
|
2024-05-21 20:29:54 +00:00
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.add_expected_use(identifier)
|
2024-04-22 05:51:34 +00:00
|
|
|
} else {
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
}
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
2024-03-17 17:36:31 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2024-06-17 14:10:06 +00:00
|
|
|
pub enum VariableData {
|
2024-03-17 17:36:31 +00:00
|
|
|
Type(Type),
|
|
|
|
Value(Value),
|
|
|
|
}
|
2024-04-22 05:51:34 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
2024-04-22 09:50:26 +00:00
|
|
|
pub struct UsageData(Arc<RwLock<UsageDataInner>>);
|
|
|
|
|
|
|
|
impl UsageData {
|
|
|
|
pub fn inner(&self) -> &Arc<RwLock<UsageDataInner>> {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct UsageDataInner {
|
2024-04-22 05:51:34 +00:00
|
|
|
pub actual: u32,
|
|
|
|
pub expected: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UsageData {
|
|
|
|
pub fn new() -> Self {
|
2024-04-22 09:50:26 +00:00
|
|
|
UsageData(Arc::new(RwLock::new(UsageDataInner {
|
2024-04-22 05:51:34 +00:00
|
|
|
actual: 0,
|
|
|
|
expected: 0,
|
2024-04-22 09:50:26 +00:00
|
|
|
})))
|
2024-04-22 05:51:34 +00:00
|
|
|
}
|
|
|
|
}
|