From fdf286cb51894e2cf25e4869e279bb943d9d80cf Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 11 Mar 2024 21:57:27 -0400 Subject: [PATCH] Add memory management --- Cargo.lock | 1 + Cargo.toml | 1 + src/abstract_tree/assignment.rs | 1 + src/abstract_tree/function_call.rs | 4 +- src/abstract_tree/identifier.rs | 16 +++-- src/abstract_tree/index.rs | 13 ++-- src/abstract_tree/mod.rs | 9 +-- src/abstract_tree/value_node.rs | 19 ----- src/abstract_tree/while.rs | 6 +- src/context.rs | 107 ++++++++++++++++++++++++----- src/parser.rs | 36 ---------- src/value.rs | 37 ---------- 12 files changed, 116 insertions(+), 134 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c413b4..fe6e8d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,6 +204,7 @@ dependencies = [ "clap", "colored", "env_logger", + "log", "stanza", ] diff --git a/Cargo.toml b/Cargo.toml index 91c9de5..2dfa786 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,5 @@ chumsky = { version = "1.0.0-alpha.6", features = ["pratt", "label"] } clap = { version = "4.5.2", features = ["derive"] } colored = "2.1.0" env_logger = "0.11.3" +log = "0.4.21" stanza = "0.5.1" diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 2f5b642..5dc0ac4 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -52,6 +52,7 @@ impl AbstractTree for Assignment { context.set_type(self.identifier.clone(), statement_type)?; } + self.identifier.validate(context)?; self.statement.validate(context)?; Ok(()) diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index c59c163..3fecf12 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -38,12 +38,12 @@ impl AbstractTree for FunctionCall { } fn run(self, context: &Context) -> Result { - let value = self.function.run(context)?.as_value()?; + let value = self.function.run(context)?.as_return_value()?; let function = value.as_function()?; let mut arguments = Vec::with_capacity(self.arguments.len()); for expression in self.arguments { - let value = expression.run(context)?.as_value()?; + let value = expression.run(context)?.as_return_value()?; arguments.push(value); } diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index b644f00..9c6449b 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -6,7 +6,6 @@ use std::{ use crate::{ context::Context, error::{RuntimeError, ValidationError}, - Value, }; use super::{AbstractTree, Action, Type}; @@ -34,7 +33,7 @@ impl AbstractTree for Identifier { } fn validate(&self, context: &Context) -> Result<(), ValidationError> { - if let Some(_) = context.get_data(self)? { + if context.add_allowance(self)? { Ok(()) } else { Err(ValidationError::VariableNotFound(self.clone())) @@ -42,12 +41,15 @@ impl AbstractTree for Identifier { } fn run(self, context: &Context) -> Result { - let value = context - .get_value(&self)? - .unwrap_or_else(Value::none) - .clone(); + let return_action = context.get_value(&self)?.map(|value| Action::Return(value)); - Ok(Action::Return(value)) + if let Some(action) = return_action { + Ok(action) + } else { + Err(RuntimeError::ValidationFailure( + ValidationError::VariableNotFound(self.clone()), + )) + } } } diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 2b8114f..10dbb73 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -1,7 +1,6 @@ use crate::{ context::Context, error::{RuntimeError, ValidationError}, - Value, }; use super::{AbstractTree, Action, Expression, Type, ValueNode}; @@ -63,11 +62,13 @@ impl AbstractTree for Index { let right_value = self.right.run(_context)?.as_return_value()?; if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) { - Ok(Action::Return( - list.get(index as usize) - .cloned() - .unwrap_or_else(Value::none), - )) + let found_item = list.get(index as usize); + + if let Some(item) = found_item { + Ok(Action::Return(item.clone())) + } else { + Ok(Action::None) + } } else { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndexWith(left_value.r#type(), right_value.r#type()), diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 8d44df0..dd9ff4a 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -44,19 +44,12 @@ pub trait AbstractTree { #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] pub enum Action { - Break, Return(Value), + Break, None, } impl Action { - pub fn as_value(self) -> Result { - match self { - Action::Return(value) => Ok(value), - _ => Err(ValidationError::ExpectedValue), - } - } - pub fn as_return_value(self) -> Result { if let Action::Return(value) = self { Ok(value) diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 98b2ea4..aeef960 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -17,7 +17,6 @@ pub enum ValueNode { Map(Vec<(Identifier, Option, Expression)>), Range(Range), String(String), - Enum(Identifier, Identifier), Function { parameters: Vec<(Identifier, Type)>, return_type: Type, @@ -43,7 +42,6 @@ impl AbstractTree for ValueNode { ValueNode::Map(_) => Type::Map, ValueNode::Range(_) => Type::Range, ValueNode::String(_) => Type::String, - ValueNode::Enum(name, _) => Type::Custom(name.clone()), ValueNode::Function { parameters, return_type, @@ -123,13 +121,6 @@ impl AbstractTree for ValueNode { } ValueNode::Range(range) => Value::range(range), ValueNode::String(string) => Value::string(string), - ValueNode::Enum(name, variant) => { - if name.as_str() == "Option" && variant.as_str() == "None" { - Value::none() - } else { - Value::r#enum(name, variant) - } - } ValueNode::Function { parameters, return_type, @@ -176,16 +167,6 @@ impl Ord for ValueNode { (Range(_), _) => Ordering::Greater, (String(left), String(right)) => left.cmp(right), (String(_), _) => Ordering::Greater, - (Enum(left_name, left_variant), Enum(right_name, right_variant)) => { - let name_cmp = left_name.cmp(right_name); - - if name_cmp.is_eq() { - left_variant.cmp(right_variant) - } else { - name_cmp - } - } - (Enum(_, _), _) => Ordering::Greater, ( Function { parameters: left_parameters, diff --git a/src/abstract_tree/while.rs b/src/abstract_tree/while.rs index d0466d6..a73c386 100644 --- a/src/abstract_tree/while.rs +++ b/src/abstract_tree/while.rs @@ -27,15 +27,15 @@ impl AbstractTree for While { self.block.validate(_context) } - fn run(self, _context: &Context) -> Result { + fn run(self, context: &Context) -> Result { while self .expression .clone() - .run(_context)? + .run(context)? .as_return_value()? .as_boolean()? { - if let Action::Break = self.block.clone().run(_context)? { + if let Action::Break = self.block.clone().run(context)? { break; } } diff --git a/src/context.rs b/src/context.rs index fe97c4f..188fb0d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -11,7 +11,25 @@ use crate::{ }; pub struct Context { - inner: Arc>>, + inner: Arc>>, +} + +#[derive(Clone, Debug)] +pub struct UsageData(Arc>); + +#[derive(Clone, Debug)] +pub struct UsageDataInner { + pub allowances: usize, + pub uses: usize, +} + +impl Default for UsageData { + fn default() -> Self { + UsageData(Arc::new(RwLock::new(UsageDataInner { + allowances: 0, + uses: 0, + }))) + } } #[derive(Clone, Debug)] @@ -27,7 +45,7 @@ impl Context { } } - pub fn with_data(data: BTreeMap) -> Self { + pub fn with_data(data: BTreeMap) -> Self { Self { inner: Arc::new(RwLock::new(data)), } @@ -36,10 +54,10 @@ impl Context { pub fn inherit_types_from(other: &Context) -> Result { let mut new_data = BTreeMap::new(); - for (identifier, value_data) in other.inner.read()?.iter() { + for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() { if let ValueData::Type(r#type) = value_data { if let Type::Function { .. } = r#type { - new_data.insert(identifier.clone(), value_data.clone()); + new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone())); } } } @@ -50,15 +68,15 @@ impl Context { pub fn inherit_data_from(other: &Context) -> Result { let mut new_data = BTreeMap::new(); - for (identifier, value_data) in other.inner.read()?.iter() { + for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() { if let ValueData::Type(r#type) = value_data { if let Type::Function { .. } = r#type { - new_data.insert(identifier.clone(), value_data.clone()); + new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone())); } } if let ValueData::Value(value) = value_data { if let ValueInner::Function { .. } = value.inner().as_ref() { - new_data.insert(identifier.clone(), value_data.clone()); + new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone())); } } } @@ -66,12 +84,41 @@ impl Context { Ok(Self::with_data(new_data)) } + pub fn add_allowance(&self, identifier: &Identifier) -> Result { + if let Some((_, usage_data)) = self.inner.read()?.get(identifier) { + usage_data.0.write()?.allowances += 1; + + Ok(true) + } else { + Ok(false) + } + } + pub fn get_data( &self, identifier: &Identifier, ) -> Result, RwLockPoisonError> { - if let Some(value_data) = self.inner.read()?.get(identifier) { - return Ok(Some(value_data.clone())); + let should_remove = + if let Some((value_data, usage_data)) = self.inner.read()?.get(identifier) { + let mut usage_data = usage_data.0.write()?; + + log::trace!("Adding use for variable: {identifier}"); + + usage_data.uses += 1; + + if usage_data.uses == usage_data.allowances { + true + } else { + return Ok(Some(value_data.clone())); + } + } else { + false + }; + + if should_remove { + log::trace!("Removing varialble: {identifier}"); + + self.inner.write()?.remove(identifier); } let value_data = match identifier.as_str() { @@ -83,7 +130,11 @@ impl Context { } pub fn get_type(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { - if let Some(ValueData::Type(r#type)) = self.inner.read()?.get(identifier) { + if let Some((ValueData::Type(r#type), usage_data)) = self.inner.read()?.get(identifier) { + log::trace!("Adding use for variable: {identifier}"); + + usage_data.0.write()?.uses += 1; + return Ok(Some(r#type.clone())); } @@ -96,8 +147,28 @@ impl Context { } pub fn get_value(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { - if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) { - return Ok(Some(value.clone())); + let should_remove = if let Some((ValueData::Value(value), usage_data)) = + self.inner.read()?.get(identifier) + { + let mut usage_data = usage_data.0.write()?; + + log::trace!("Adding use for variable: {identifier}"); + + usage_data.uses += 1; + + if usage_data.uses == usage_data.allowances { + true + } else { + return Ok(Some(value.clone())); + } + } else { + false + }; + + if should_remove { + log::trace!("Removing varialble: {identifier}"); + + self.inner.write()?.remove(identifier); } let value = match identifier.as_str() { @@ -111,15 +182,19 @@ impl Context { pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> { self.inner .write()? - .insert(identifier, ValueData::Type(r#type)); + .insert(identifier, (ValueData::Type(r#type), UsageData::default())); Ok(()) } pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> { - self.inner - .write()? - .insert(identifier, ValueData::Value(value)); + let mut inner = self.inner.write()?; + + if let Some((_value_data, usage_data)) = inner.remove(&identifier) { + inner.insert(identifier, (ValueData::Value(value), usage_data)); + } else { + inner.insert(identifier, (ValueData::Value(value), UsageData::default())); + } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index 16557cd..869e4a7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -169,13 +169,6 @@ pub fn parser<'src>() -> DustParser<'src> { ) .map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list))); - let r#enum = identifier - .clone() - .then_ignore(just(Token::Control(Control::DoubleColon))) - .then(identifier.clone()) - .map(|(name, variant)| Expression::Value(ValueNode::Enum(name, variant))) - .boxed(); - let function = identifier .clone() .then(type_specification.clone()) @@ -219,7 +212,6 @@ pub fn parser<'src>() -> DustParser<'src> { identifier_expression.clone(), basic_value.clone(), list.clone(), - r#enum.clone(), expression.clone().delimited_by( just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenClose)), @@ -289,7 +281,6 @@ pub fn parser<'src>() -> DustParser<'src> { choice(( function, range, - r#enum, logic_math_and_index, identifier_expression, list, @@ -661,22 +652,6 @@ mod tests { ); } - #[test] - fn assignment_with_custom_type() { - assert_eq!( - parse(&lex("foobar: Foo = Foo::Bar").unwrap()).unwrap()[0].0, - Statement::Assignment(Assignment::new( - Identifier::new("foobar"), - Some(Type::Custom(Identifier::new("Foo"))), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value(ValueNode::Enum( - Identifier::new("Foo"), - Identifier::new("Bar") - ))) - )), - ); - } - #[test] fn assignment_with_list_types() { assert_eq!( @@ -755,17 +730,6 @@ mod tests { ); } - #[test] - fn r#enum() { - assert_eq!( - parse(&lex("Option::None").unwrap()).unwrap()[0].0, - Statement::Expression(Expression::Value(ValueNode::Enum( - Identifier::new("Option"), - Identifier::new("None") - ))) - ); - } - #[test] fn list() { assert_eq!( diff --git a/src/value.rs b/src/value.rs index ac4c0a5..018cb70 100644 --- a/src/value.rs +++ b/src/value.rs @@ -18,17 +18,6 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -pub static NONE: OnceLock = OnceLock::new(); - -fn get_none<'a>() -> &'a Value { - NONE.get_or_init(|| { - Value(Arc::new(ValueInner::Enum( - Identifier::new("Option"), - Identifier::new("None"), - ))) - }) -} - #[derive(Clone, Debug, PartialEq)] pub struct Value(Arc); @@ -37,10 +26,6 @@ impl Value { &self.0 } - pub fn none() -> Self { - get_none().clone() - } - pub fn boolean(boolean: bool) -> Self { Value(Arc::new(ValueInner::Boolean(boolean))) } @@ -69,10 +54,6 @@ impl Value { Value(Arc::new(ValueInner::String(string))) } - pub fn r#enum(name: Identifier, variant: Identifier) -> Self { - Value(Arc::new(ValueInner::Enum(name, variant))) - } - pub fn function(parameters: Vec<(Identifier, Type)>, return_type: Type, body: Block) -> Self { Value(Arc::new(ValueInner::Function(Function::Parsed( ParsedFunction { @@ -104,7 +85,6 @@ impl Value { ValueInner::Map(_) => Type::Map, ValueInner::Range(_) => Type::Range, ValueInner::String(_) => Type::String, - ValueInner::Enum(name, _) => Type::Custom(name.clone()), ValueInner::Function(_) => todo!(), } } @@ -149,10 +129,6 @@ impl Value { } } - pub fn is_none(&self) -> bool { - self == get_none() - } - pub fn add(&self, other: &Self) -> Result { match (self.inner().as_ref(), other.inner().as_ref()) { (ValueInner::Integer(left), ValueInner::Integer(right)) => { @@ -236,8 +212,6 @@ impl Display for Value { } ValueInner::Range(_) => todo!(), ValueInner::String(string) => write!(f, "{string}"), - - ValueInner::Enum(_, _) => todo!(), ValueInner::Function(Function::Parsed(ParsedFunction { parameters, return_type, @@ -282,7 +256,6 @@ pub enum ValueInner { Map(BTreeMap), Range(Range), String(String), - Enum(Identifier, Identifier), } impl Eq for ValueInner {} @@ -320,16 +293,6 @@ impl Ord for ValueInner { (Range(_), _) => Ordering::Greater, (String(left), String(right)) => left.cmp(right), (String(_), _) => Ordering::Greater, - (Enum(name_left, variant_left), Enum(name_right, variant_right)) => { - let name_cmp = name_left.cmp(name_right); - - if name_cmp.is_eq() { - variant_left.cmp(variant_right) - } else { - name_cmp - } - } - (Enum(..), _) => Ordering::Greater, (Function(left), Function(right)) => left.cmp(right), (Function(_), _) => Ordering::Greater, }