diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index 963b78e..04a1a92 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -163,112 +163,3 @@ impl AbstractNode for Assignment { Ok(Action::None) } } - -#[cfg(test)] -mod tests { - use crate::{ - abstract_tree::{Expression, ValueNode, WithPos}, - error::TypeConflict, - }; - - use super::*; - - #[test] - fn assign_value() { - let mut context = Context::new(); - - Assignment::new( - Identifier::new("foobar").with_position((0, 0)), - None, - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::Integer(42).with_position((0, 0)), - )), - ) - .run(&mut context, true) - .unwrap(); - - assert_eq!( - context.use_value(&Identifier::new("foobar")), - Ok(Some(Value::integer(42))) - ) - } - - #[test] - fn add_assign_value() { - let mut context = Context::new(); - - context - .set_value(Identifier::new("foobar"), Value::integer(1)) - .unwrap(); - - Assignment::new( - Identifier::new("foobar").with_position((0, 0)), - None, - AssignmentOperator::AddAssign, - Statement::Expression(Expression::Value( - ValueNode::Integer(41).with_position((0, 0)), - )), - ) - .run(&mut context, true) - .unwrap(); - - assert_eq!( - context.use_value(&Identifier::new("foobar")), - Ok(Some(Value::integer(42))) - ) - } - - #[test] - fn subtract_assign_value() { - let mut context = Context::new(); - - context - .set_value(Identifier::new("foobar"), Value::integer(43)) - .unwrap(); - - Assignment::new( - Identifier::new("foobar").with_position((0, 0)), - None, - AssignmentOperator::SubAssign, - Statement::Expression(Expression::Value( - ValueNode::Integer(1).with_position((0, 0)), - )), - ) - .run(&mut context, true) - .unwrap(); - - assert_eq!( - context.use_value(&Identifier::new("foobar")), - Ok(Some(Value::integer(42))) - ) - } - - #[test] - fn type_check() { - let validation = Assignment::new( - Identifier::new("foobar").with_position((0, 0)), - Some(WithPosition { - item: Type::Boolean, - position: (0, 0).into(), - }), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::Integer(42).with_position((0, 0)), - )), - ) - .validate(&Context::new()); - - assert_eq!( - validation, - Err(ValidationError::TypeCheck { - conflict: TypeConflict { - actual: Type::Integer, - expected: Type::Boolean - }, - actual_position: (0, 0).into(), - expected_position: (0, 0).into(), - }) - ) - } -} diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs index 225bcdd..7c1cff4 100644 --- a/dust-lang/src/abstract_tree/list_index.rs +++ b/dust-lang/src/abstract_tree/list_index.rs @@ -48,6 +48,9 @@ impl AbstractNode for ListIndex { } fn validate(&self, context: &Context) -> Result<(), ValidationError> { + self.left.validate(context)?; + self.right.validate(context)?; + let left_type = self.left.expected_type(context)?; match left_type { diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs index 176a106..02b7940 100644 --- a/dust-lang/src/abstract_tree/loop.rs +++ b/dust-lang/src/abstract_tree/loop.rs @@ -1,5 +1,3 @@ -use std::cmp::Ordering; - use crate::{ context::Context, error::{RuntimeError, ValidationError}, @@ -7,7 +5,7 @@ use crate::{ use super::{AbstractNode, Action, Statement, Type}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Loop { statements: Vec, } @@ -34,7 +32,7 @@ impl AbstractNode for Loop { fn run(self, _context: &mut Context, _clear_variables: bool) -> Result { loop { for statement in &self.statements { - let action = statement.clone().run(_context, _clear_variables)?; + let action = statement.clone().run(_context, false)?; match action { Action::Return(_) => {} @@ -45,23 +43,3 @@ impl AbstractNode for Loop { } } } - -impl Eq for Loop {} - -impl PartialEq for Loop { - fn eq(&self, other: &Self) -> bool { - self.statements.eq(&other.statements) - } -} - -impl PartialOrd for Loop { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Loop { - fn cmp(&self, other: &Self) -> Ordering { - self.statements.cmp(&other.statements) - } -} diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs index 4725ad2..fd47c96 100644 --- a/dust-lang/src/abstract_tree/statement.rs +++ b/dust-lang/src/abstract_tree/statement.rs @@ -72,23 +72,49 @@ impl AbstractNode for Statement { fn run(self, context: &mut Context, clear_variables: bool) -> Result { let result = match self { - Statement::Assignment(assignment) => assignment.item.run(context, clear_variables), + Statement::Assignment(assignment) => { + let run_result = assignment.item.run(context, clear_variables); + + if clear_variables { + context.clean()?; + } + + run_result + } Statement::AsyncBlock(async_block) => async_block.item.run(context, clear_variables), Statement::Block(block) => block.item.run(context, clear_variables), Statement::Break(_) => Ok(Action::Break), - Statement::Expression(expression) => expression.run(context, clear_variables), - Statement::IfElse(if_else) => if_else.item.run(context, clear_variables), + Statement::Expression(expression) => { + let run_result = expression.run(context, clear_variables); + + if clear_variables { + context.clean()?; + } + + run_result + } + Statement::IfElse(if_else) => { + let run_result = if_else.item.run(context, clear_variables); + + if clear_variables { + context.clean()?; + } + + run_result + } Statement::Loop(r#loop) => r#loop.item.run(context, clear_variables), Statement::While(r#while) => r#while.item.run(context, clear_variables), Statement::StructureDefinition(structure_definition) => { - structure_definition.item.run(context, clear_variables) + let run_result = structure_definition.item.run(context, clear_variables); + + if clear_variables { + context.clean()?; + } + + run_result } }; - if clear_variables { - context.clean()?; - } - result } } diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 2a131af..5ffd058 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -83,12 +83,11 @@ impl Context { } pub fn use_value(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { - if let Some((ValueData::Value(value), usage_data)) = - self.variables.write()?.get_mut(identifier) + if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier) { log::trace!("Using {identifier}'s value."); - usage_data.actual += 1; + usage_data.inner().write()?.actual += 1; Ok(Some(value.clone())) } else { @@ -123,21 +122,13 @@ impl Context { Ok(()) } - pub fn remove(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { - let removed = self - .variables - .write()? - .remove(identifier) - .map(|(value_data, _)| value_data); - - Ok(removed) - } - pub fn clean(&mut self) -> Result<(), RwLockPoisonError> { self.variables .write()? .retain(|identifier, (_, usage_data)| { - if usage_data.actual < usage_data.expected { + let usage = usage_data.inner().read().unwrap(); + + if usage.actual < usage.expected { true } else { log::trace!("Removing variable {identifier}."); @@ -150,12 +141,10 @@ impl Context { } pub fn add_expected_use(&self, identifier: &Identifier) -> Result { - let mut variables = self.variables.write()?; - - if let Some((_, usage_data)) = variables.get_mut(identifier) { + if let Some((_, usage_data)) = self.variables.read()?.get(identifier) { log::trace!("Adding expected use for variable {identifier}."); - usage_data.expected += 1; + usage_data.inner().write()?.expected += 1; Ok(true) } else { @@ -171,16 +160,25 @@ pub enum ValueData { } #[derive(Clone, Debug)] -pub struct UsageData { +pub struct UsageData(Arc>); + +impl UsageData { + pub fn inner(&self) -> &Arc> { + &self.0 + } +} + +#[derive(Clone, Debug)] +pub struct UsageDataInner { pub actual: u32, pub expected: u32, } impl UsageData { pub fn new() -> Self { - Self { + UsageData(Arc::new(RwLock::new(UsageDataInner { actual: 0, expected: 0, - } + }))) } }