diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index 423f4b1..d0da851 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -39,11 +39,11 @@ impl Assignment { } impl AbstractNode for Assignment { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { Ok(Type::None) } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { let statement_type = self.statement.expected_type(context)?; if let Some(WithPosition { diff --git a/dust-lang/src/abstract_tree/async_block.rs b/dust-lang/src/abstract_tree/async_block.rs index cc92d80..fdc0b32 100644 --- a/dust-lang/src/abstract_tree/async_block.rs +++ b/dust-lang/src/abstract_tree/async_block.rs @@ -21,11 +21,11 @@ impl AsyncBlock { } impl AbstractNode for AsyncBlock { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { self.statements.last().unwrap().expected_type(_context) } - fn validate(&self, _context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, _context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { for statement in &self.statements { statement.validate(_context, manage_memory)?; } @@ -33,7 +33,7 @@ impl AbstractNode for AsyncBlock { Ok(()) } - fn run(self, _context: &mut Context, manage_memory: bool) -> Result { + fn run(self, _context: &mut Context, _manage_memory: bool) -> Result { let statement_count = self.statements.len(); let final_result = RwLock::new(Ok(Action::None)); @@ -41,7 +41,7 @@ impl AbstractNode for AsyncBlock { .into_par_iter() .enumerate() .find_map_first(|(index, statement)| { - let result = statement.run(&mut _context.clone(), manage_memory); + let result = statement.run(&mut _context.clone(), false); if index == statement_count - 1 { let get_write_lock = final_result.write(); diff --git a/dust-lang/src/abstract_tree/block.rs b/dust-lang/src/abstract_tree/block.rs index e43b560..5597a7c 100644 --- a/dust-lang/src/abstract_tree/block.rs +++ b/dust-lang/src/abstract_tree/block.rs @@ -21,7 +21,7 @@ impl Block { } impl AbstractNode for Block { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { if let Some(statement) = self.statements.last() { statement.expected_type(_context) } else { @@ -29,7 +29,11 @@ impl AbstractNode for Block { } } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { for statement in &self.statements { statement.validate(_context, _manage_memory)?; } @@ -88,6 +92,6 @@ mod tests { )), ]); - assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) + assert_eq!(block.expected_type(&mut Context::new()), Ok(Type::Integer)) } } diff --git a/dust-lang/src/abstract_tree/built_in_function_call.rs b/dust-lang/src/abstract_tree/built_in_function_call.rs index 8190580..e710d52 100644 --- a/dust-lang/src/abstract_tree/built_in_function_call.rs +++ b/dust-lang/src/abstract_tree/built_in_function_call.rs @@ -18,7 +18,7 @@ pub enum BuiltInFunctionCall { } impl AbstractNode for BuiltInFunctionCall { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { match self { BuiltInFunctionCall::ReadLine => Ok(Type::String), BuiltInFunctionCall::Sleep(_) => Ok(Type::None), @@ -26,7 +26,11 @@ impl AbstractNode for BuiltInFunctionCall { } } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { match self { BuiltInFunctionCall::ReadLine => Ok(()), BuiltInFunctionCall::Sleep(expression) => expression.validate(_context, _manage_memory), diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs index 40933e1..9b58498 100644 --- a/dust-lang/src/abstract_tree/expression.rs +++ b/dust-lang/src/abstract_tree/expression.rs @@ -37,7 +37,7 @@ impl Expression { } impl AbstractNode for Expression { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { match self { Expression::FunctionCall(function_call) => function_call.item.expected_type(_context), Expression::Identifier(identifier) => { @@ -61,7 +61,7 @@ impl AbstractNode for Expression { } } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { match self { Expression::FunctionCall(function_call) => { function_call.item.validate(context, manage_memory) diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index dac1e8f..5562e9c 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -28,7 +28,7 @@ impl FunctionCall { } impl AbstractNode for FunctionCall { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { let function_node_type = self.function.expected_type(_context)?; if let Type::Function { return_type, .. } = function_node_type { @@ -41,7 +41,7 @@ impl AbstractNode for FunctionCall { } } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { self.function.validate(context, manage_memory)?; for expression in &self.arguments { diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs index 3ae0e7c..bae77b2 100644 --- a/dust-lang/src/abstract_tree/if_else.rs +++ b/dust-lang/src/abstract_tree/if_else.rs @@ -31,11 +31,11 @@ impl IfElse { } impl AbstractNode for IfElse { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { self.if_block.item.expected_type(_context) } - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> { self.if_expression.validate(context, manage_memory)?; self.if_block.item.validate(context, manage_memory)?; diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index ec27318..e104299 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -18,7 +18,7 @@ impl ListIndex { } impl AbstractNode for ListIndex { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { let left_type = self.left.expected_type(_context)?; if let ( @@ -47,7 +47,7 @@ impl AbstractNode for ListIndex { } } - fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> { self.left.validate(context, _manage_memory)?; self.right.validate(context, _manage_memory)?; diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs index e2aa975..502ec96 100644 --- a/dust-lang/src/abstract_tree/logic.rs +++ b/dust-lang/src/abstract_tree/logic.rs @@ -21,11 +21,11 @@ pub enum Logic { } impl AbstractNode for Logic { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { Ok(Type::Boolean) } - fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> { match self { Logic::Equal(left, right) | Logic::NotEqual(left, right) diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs index a2cdd78..506fa44 100644 --- a/dust-lang/src/abstract_tree/loop.rs +++ b/dust-lang/src/abstract_tree/loop.rs @@ -17,11 +17,15 @@ impl Loop { } impl AbstractNode for Loop { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { Ok(Type::None) } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { for statement in &self.statements { statement.validate(_context, false)?; } diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index 9452d78..79c7dfe 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -23,7 +23,7 @@ impl MapIndex { } impl AbstractNode for MapIndex { - fn expected_type(&self, context: &Context) -> Result { + fn expected_type(&self, context: &mut Context) -> Result { if let (Expression::Identifier(collection_identifier), index) = (&self.collection, &self.index) { @@ -105,7 +105,11 @@ impl AbstractNode for MapIndex { }) } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { self.collection.validate(_context, _manage_memory) } diff --git a/dust-lang/src/abstract_tree/math.rs b/dust-lang/src/abstract_tree/math.rs index 293bf13..dde5079 100644 --- a/dust-lang/src/abstract_tree/math.rs +++ b/dust-lang/src/abstract_tree/math.rs @@ -17,7 +17,7 @@ pub enum Math { } impl AbstractNode for Math { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { match self { Math::Add(left, right) | Math::Subtract(left, right) @@ -40,7 +40,7 @@ impl AbstractNode for Math { } } - fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> { match self { Math::Add(left, right) => { let left_position = left.position(); diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index a1191e7..12c7102 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -182,7 +182,7 @@ impl Index for AbstractTree { } pub trait AbstractNode: Sized { - fn expected_type(&self, context: &Context) -> Result; - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError>; + fn expected_type(&self, context: &mut Context) -> Result; + fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError>; fn run(self, context: &mut Context, manage_memory: bool) -> Result; } diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index bed7991..cd23513 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -38,7 +38,7 @@ impl Statement { } impl AbstractNode for Statement { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { match self { Statement::Assignment(assignment) => assignment.item.expected_type(_context), Statement::AsyncBlock(async_block) => async_block.item.expected_type(_context), @@ -54,7 +54,11 @@ impl AbstractNode for Statement { } } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { match self { Statement::Assignment(assignment) => assignment.item.validate(_context, _manage_memory), Statement::AsyncBlock(async_block) => { diff --git a/dust-lang/src/abstract_tree/structure_definition.rs b/dust-lang/src/abstract_tree/structure_definition.rs index abee81f..366a454 100644 --- a/dust-lang/src/abstract_tree/structure_definition.rs +++ b/dust-lang/src/abstract_tree/structure_definition.rs @@ -19,11 +19,15 @@ impl StructureDefinition { } impl AbstractNode for StructureDefinition { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { Ok(Type::None) } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { Ok(()) } diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index fdec583..a13c342 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -144,11 +144,15 @@ impl Type { } impl AbstractNode for Type { - fn expected_type(&self, _: &Context) -> Result { + fn expected_type(&self, _: &mut Context) -> Result { Ok(Type::None) } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { Ok(()) } diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 27280c9..2202434 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -31,7 +31,7 @@ pub enum ValueNode { } impl AbstractNode for ValueNode { - fn expected_type(&self, context: &Context) -> Result { + fn expected_type(&self, context: &mut Context) -> Result { let r#type = match self { ValueNode::Boolean(_) => Type::Boolean, ValueNode::Float(_) => Type::Float, @@ -91,7 +91,7 @@ impl AbstractNode for ValueNode { Ok(r#type) } - fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> { if let ValueNode::Map(map_assignments) = self { for (_identifier, r#type, expression) in map_assignments { if let Some(expected_type) = r#type { @@ -117,7 +117,7 @@ impl AbstractNode for ValueNode { body, } = self { - let function_context = Context::new(); + let mut function_context = Context::new(); function_context.inherit_types_from(context)?; @@ -131,9 +131,9 @@ impl AbstractNode for ValueNode { function_context.set_type(identifier.clone(), r#type.item.clone())?; } - body.item.validate(&function_context, _manage_memory)?; + body.item.validate(&mut function_context, _manage_memory)?; - let actual_return_type = body.item.expected_type(&function_context)?; + let actual_return_type = body.item.expected_type(&mut function_context)?; return_type .item diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs index ddc92fa..7a42c31 100644 --- a/dust-lang/src/abstract_tree/while.rs +++ b/dust-lang/src/abstract_tree/while.rs @@ -23,11 +23,15 @@ impl While { } impl AbstractNode for While { - fn expected_type(&self, _context: &Context) -> Result { + fn expected_type(&self, _context: &mut Context) -> Result { Ok(Type::None) } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + fn validate( + &self, + _context: &mut Context, + _manage_memory: bool, + ) -> Result<(), ValidationError> { self.expression.validate(_context, _manage_memory)?; for statement in &self.statements { diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 6d1aef2..256d070 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -78,12 +78,16 @@ impl Context { } } - pub fn use_value(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { + pub fn use_value( + &mut self, + identifier: &Identifier, + ) -> Result, RwLockPoisonError> { if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier) { log::trace!("Using {identifier}'s value."); usage_data.inner().write()?.actual += 1; + self.is_clean = false; Ok(Some(value.clone())) } else { @@ -111,7 +115,11 @@ impl Context { Ok(()) } - pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> { + pub fn set_value( + &mut self, + identifier: Identifier, + value: Value, + ) -> Result<(), RwLockPoisonError> { log::debug!("Setting {identifier} to value {value}."); let mut variables = self.variables.write()?; @@ -156,6 +164,22 @@ impl Context { Ok(()) } + pub fn is_clean(&mut self) -> Result { + if self.is_clean { + 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) + } + } + pub fn add_expected_use(&self, identifier: &Identifier) -> Result { if let Some((_, usage_data)) = self.variables.read()?.get(identifier) { log::trace!("Adding expected use for variable {identifier}.");