Refine memory management

This commit is contained in:
Jeff 2024-04-22 05:50:26 -04:00
parent 8478d59000
commit bcd8e7c669
5 changed files with 58 additions and 162 deletions

View File

@ -163,112 +163,3 @@ impl AbstractNode for Assignment {
Ok(Action::None) 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(),
})
)
}
}

View File

@ -48,6 +48,9 @@ impl AbstractNode for ListIndex {
} }
fn validate(&self, context: &Context) -> Result<(), ValidationError> { fn validate(&self, context: &Context) -> Result<(), ValidationError> {
self.left.validate(context)?;
self.right.validate(context)?;
let left_type = self.left.expected_type(context)?; let left_type = self.left.expected_type(context)?;
match left_type { match left_type {

View File

@ -1,5 +1,3 @@
use std::cmp::Ordering;
use crate::{ use crate::{
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
@ -7,7 +5,7 @@ use crate::{
use super::{AbstractNode, Action, Statement, Type}; use super::{AbstractNode, Action, Statement, Type};
#[derive(Clone, Debug)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Loop { pub struct Loop {
statements: Vec<Statement>, statements: Vec<Statement>,
} }
@ -34,7 +32,7 @@ impl AbstractNode for Loop {
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> { fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
loop { loop {
for statement in &self.statements { for statement in &self.statements {
let action = statement.clone().run(_context, _clear_variables)?; let action = statement.clone().run(_context, false)?;
match action { match action {
Action::Return(_) => {} 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<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Loop {
fn cmp(&self, other: &Self) -> Ordering {
self.statements.cmp(&other.statements)
}
}

View File

@ -72,23 +72,49 @@ impl AbstractNode for Statement {
fn run(self, context: &mut Context, clear_variables: bool) -> Result<Action, RuntimeError> { fn run(self, context: &mut Context, clear_variables: bool) -> Result<Action, RuntimeError> {
let result = match self { 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::AsyncBlock(async_block) => async_block.item.run(context, clear_variables),
Statement::Block(block) => block.item.run(context, clear_variables), Statement::Block(block) => block.item.run(context, clear_variables),
Statement::Break(_) => Ok(Action::Break), Statement::Break(_) => Ok(Action::Break),
Statement::Expression(expression) => expression.run(context, clear_variables), Statement::Expression(expression) => {
Statement::IfElse(if_else) => if_else.item.run(context, clear_variables), 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::Loop(r#loop) => r#loop.item.run(context, clear_variables),
Statement::While(r#while) => r#while.item.run(context, clear_variables), Statement::While(r#while) => r#while.item.run(context, clear_variables),
Statement::StructureDefinition(structure_definition) => { 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 result
} }
} }

View File

@ -83,12 +83,11 @@ impl Context {
} }
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> { pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
if let Some((ValueData::Value(value), usage_data)) = if let Some((ValueData::Value(value), usage_data)) = self.variables.read()?.get(identifier)
self.variables.write()?.get_mut(identifier)
{ {
log::trace!("Using {identifier}'s value."); log::trace!("Using {identifier}'s value.");
usage_data.actual += 1; usage_data.inner().write()?.actual += 1;
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else { } else {
@ -123,21 +122,13 @@ impl Context {
Ok(()) Ok(())
} }
pub fn remove(&self, identifier: &Identifier) -> Result<Option<ValueData>, RwLockPoisonError> {
let removed = self
.variables
.write()?
.remove(identifier)
.map(|(value_data, _)| value_data);
Ok(removed)
}
pub fn clean(&mut self) -> Result<(), RwLockPoisonError> { pub fn clean(&mut self) -> Result<(), RwLockPoisonError> {
self.variables self.variables
.write()? .write()?
.retain(|identifier, (_, usage_data)| { .retain(|identifier, (_, usage_data)| {
if usage_data.actual < usage_data.expected { let usage = usage_data.inner().read().unwrap();
if usage.actual < usage.expected {
true true
} else { } else {
log::trace!("Removing variable {identifier}."); log::trace!("Removing variable {identifier}.");
@ -150,12 +141,10 @@ impl Context {
} }
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> { pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
let mut variables = self.variables.write()?; if let Some((_, usage_data)) = self.variables.read()?.get(identifier) {
if let Some((_, usage_data)) = variables.get_mut(identifier) {
log::trace!("Adding expected use for variable {identifier}."); log::trace!("Adding expected use for variable {identifier}.");
usage_data.expected += 1; usage_data.inner().write()?.expected += 1;
Ok(true) Ok(true)
} else { } else {
@ -171,16 +160,25 @@ pub enum ValueData {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct UsageData { pub struct UsageData(Arc<RwLock<UsageDataInner>>);
impl UsageData {
pub fn inner(&self) -> &Arc<RwLock<UsageDataInner>> {
&self.0
}
}
#[derive(Clone, Debug)]
pub struct UsageDataInner {
pub actual: u32, pub actual: u32,
pub expected: u32, pub expected: u32,
} }
impl UsageData { impl UsageData {
pub fn new() -> Self { pub fn new() -> Self {
Self { UsageData(Arc::new(RwLock::new(UsageDataInner {
actual: 0, actual: 0,
expected: 0, expected: 0,
} })))
} }
} }