diff --git a/Cargo.lock b/Cargo.lock index 3f3a953..697f3f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,6 +152,7 @@ version = "0.5.0" dependencies = [ "annotate-snippets", "env_logger", + "log", "rand", "rayon", "serde", @@ -184,9 +185,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -232,9 +233,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" diff --git a/dust-lang/Cargo.toml b/dust-lang/Cargo.toml index 5a7f656..34e9db6 100644 --- a/dust-lang/Cargo.toml +++ b/dust-lang/Cargo.toml @@ -11,7 +11,11 @@ repository.workspace = true [dependencies] annotate-snippets = "0.11.4" env_logger = "0.11.3" +log = "0.4.22" rand = "0.8.5" rayon = "1.9.0" serde = { version = "1.0.203", features = ["derive"] } serde_json = "1.0.117" + +[dev-dependencies] +env_logger = "0.11.5" diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index e1da7eb..a734513 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -127,7 +127,7 @@ impl Statement { Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(), Statement::Constant(value) => Some(value.r#type(context)), Statement::FunctionCall { function, .. } => function.inner.expected_type(context), - Statement::Identifier(identifier) => context.get_type(identifier).cloned(), + Statement::Identifier(identifier) => context.get_type(identifier), Statement::If { .. } => None, Statement::IfElse { if_body, .. } => if_body.inner.expected_type(context), Statement::IfElseIf { .. } => None, diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index d22104f..bf529f9 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -67,38 +67,38 @@ impl<'a> Analyzer<'a> { pub fn analyze(&mut self) -> Result<(), AnalyzerError> { for node in &self.abstract_tree.nodes { - self.analyze_node(node)?; + self.analyze_statement(node)?; } Ok(()) } - fn analyze_node(&mut self, node: &Node) -> Result<(), AnalyzerError> { + fn analyze_statement(&mut self, node: &Node) -> Result<(), AnalyzerError> { match &node.inner { Statement::BinaryOperation { left, operator, right, } => { - if let BinaryOperator::Assign = operator.inner { + if let BinaryOperator::Assign | BinaryOperator::AddAssign = operator.inner { + self.analyze_statement(right)?; + if let Statement::Identifier(identifier) = &left.inner { - self.analyze_node(right)?; - - let right_type = right.inner.expected_type(self.context); - - self.context.set_type( - identifier.clone(), - right_type.ok_or(AnalyzerError::ExpectedValue { + let right_type = right.inner.expected_type(self.context).ok_or( + AnalyzerError::ExpectedValue { actual: right.as_ref().clone(), - })?, - ); + }, + )?; + + self.context + .set_type(identifier.clone(), right_type, left.position); return Ok(()); } } - self.analyze_node(left)?; - self.analyze_node(right)?; + self.analyze_statement(left)?; + self.analyze_statement(right)?; let left_type = left.inner.expected_type(self.context); let right_type = right.inner.expected_type(self.context); @@ -131,7 +131,7 @@ impl<'a> Analyzer<'a> { } Statement::Block(statements) => { for statement in statements { - self.analyze_node(statement)?; + self.analyze_statement(statement)?; } } Statement::BuiltInFunctionCall { @@ -143,7 +143,7 @@ impl<'a> Analyzer<'a> { if let Some(arguments) = value_arguments { for argument in arguments { - self.analyze_node(argument)?; + self.analyze_statement(argument)?; } if arguments.len() != value_parameters.len() { @@ -195,16 +195,16 @@ impl<'a> Analyzer<'a> { value_arguments, .. } => { - self.analyze_node(function)?; + self.analyze_statement(function)?; if let Some(arguments) = value_arguments { for argument in arguments { - self.analyze_node(argument)?; + self.analyze_statement(argument)?; } } } Statement::Identifier(identifier) => { - let exists = self.context.add_allowed_use(identifier); + let exists = self.context.update_last_position(identifier, node.position); if !exists { return Err(AnalyzerError::UndefinedVariable { @@ -213,7 +213,7 @@ impl<'a> Analyzer<'a> { } } Statement::If { condition, body } => { - self.analyze_node(condition)?; + self.analyze_statement(condition)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { // Condition is valid @@ -223,14 +223,14 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_node(body)?; + self.analyze_statement(body)?; } Statement::IfElse { condition, if_body, else_body, } => { - self.analyze_node(condition)?; + self.analyze_statement(condition)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { // Condition is valid @@ -240,15 +240,15 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_node(if_body)?; - self.analyze_node(else_body)?; + self.analyze_statement(if_body)?; + self.analyze_statement(else_body)?; } Statement::IfElseIf { condition, if_body, else_ifs, } => { - self.analyze_node(condition)?; + self.analyze_statement(condition)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { // Condition is valid @@ -258,10 +258,10 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_node(if_body)?; + self.analyze_statement(if_body)?; for (condition, body) in else_ifs { - self.analyze_node(condition)?; + self.analyze_statement(condition)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { // Condition is valid @@ -271,7 +271,7 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_node(body)?; + self.analyze_statement(body)?; } } Statement::IfElseIfElse { @@ -280,7 +280,7 @@ impl<'a> Analyzer<'a> { else_ifs, else_body, } => { - self.analyze_node(condition)?; + self.analyze_statement(condition)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { // Condition is valid @@ -290,10 +290,10 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_node(if_body)?; + self.analyze_statement(if_body)?; for (condition, body) in else_ifs { - self.analyze_node(condition)?; + self.analyze_statement(condition)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { // Condition is valid @@ -303,31 +303,31 @@ impl<'a> Analyzer<'a> { }); } - self.analyze_node(body)?; + self.analyze_statement(body)?; } - self.analyze_node(else_body)?; + self.analyze_statement(else_body)?; } Statement::List(statements) => { for statement in statements { - self.analyze_node(statement)?; + self.analyze_statement(statement)?; } } Statement::Map(properties) => { for (_key, value_node) in properties { - self.analyze_node(value_node)?; + self.analyze_statement(value_node)?; } } Statement::Nil(node) => { - self.analyze_node(node)?; + self.analyze_statement(node)?; } Statement::PropertyAccess(left, right) => { - self.analyze_node(left)?; + self.analyze_statement(left)?; if let Statement::Identifier(_) = right.inner { // Do not expect a value for property accessors } else { - self.analyze_node(right)?; + self.analyze_statement(right)?; } if let Some(Type::List { .. }) = left.inner.expected_type(self.context) { @@ -353,8 +353,8 @@ impl<'a> Analyzer<'a> { } } Statement::While { condition, body } => { - self.analyze_node(condition)?; - self.analyze_node(body)?; + self.analyze_statement(condition)?; + self.analyze_statement(body)?; if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { } else { diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 27b2d70..231cc18 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -1,94 +1,111 @@ //! Garbage-collecting context for variables. -use std::collections::HashMap; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; -use crate::{Identifier, Type, Value}; +use crate::{Identifier, Span, Type, Value}; /// Garbage-collecting context for variables. #[derive(Debug, Clone)] pub struct Context { - variables: HashMap, - is_garbage_collected: bool, + variables: Arc>>, + is_garbage_collected_to: Arc>, } impl Context { pub fn new() -> Self { Self { - variables: HashMap::new(), - is_garbage_collected: true, + variables: Arc::new(RwLock::new(HashMap::new())), + is_garbage_collected_to: Arc::new(RwLock::new(0)), } } + pub fn variable_count(&self) -> usize { + self.variables.read().unwrap().len() + } + pub fn contains(&self, identifier: &Identifier) -> bool { - self.variables.contains_key(identifier) + self.variables.read().unwrap().contains_key(identifier) } - pub fn get(&self, identifier: &Identifier) -> Option<&(VariableData, UsageData)> { - self.variables.get(identifier) + pub fn get(&self, identifier: &Identifier) -> Option<(VariableData, Span)> { + self.variables.read().unwrap().get(identifier).cloned() } - pub fn get_type(&self, identifier: &Identifier) -> Option<&Type> { - match self.variables.get(identifier) { - Some((VariableData::Type(r#type), _)) => Some(r#type), + pub fn get_type(&self, identifier: &Identifier) -> Option { + match self.variables.read().unwrap().get(identifier) { + Some((VariableData::Type(r#type), _)) => Some(r#type.clone()), _ => None, } } - pub fn get_variable_data(&self, identifier: &Identifier) -> Option<&VariableData> { - match self.variables.get(identifier) { - Some((variable_data, _)) => Some(variable_data), + pub fn get_variable_data(&self, identifier: &Identifier) -> Option { + match self.variables.read().unwrap().get(identifier) { + Some((variable_data, _)) => Some(variable_data.clone()), _ => None, } } - pub fn get_value(&self, identifier: &Identifier) -> Option<&Value> { - match self.variables.get(identifier) { - Some((VariableData::Value(value), _)) => Some(value), + pub fn get_value(&self, identifier: &Identifier) -> Option { + match self.variables.read().unwrap().get(identifier) { + Some((VariableData::Value(value), _)) => Some(value.clone()), _ => None, } } - pub fn use_value(&mut self, identifier: &Identifier) -> Option<&Value> { - self.is_garbage_collected = false; + pub fn set_type(&mut self, identifier: Identifier, r#type: Type, position: Span) { + log::trace!("Setting {identifier} to type {type} at {position:?}"); - match self.variables.get_mut(identifier) { - Some((VariableData::Value(value), usage_data)) => { - usage_data.used += 1; - - Some(value) - } - _ => None, - } - } - - pub fn set_type(&mut self, identifier: Identifier, r#type: Type) { - self.is_garbage_collected = false; - - self.variables.insert( - identifier, - (VariableData::Type(r#type), UsageData::default()), - ); + self.variables + .write() + .unwrap() + .insert(identifier, (VariableData::Type(r#type), position)); } pub fn set_value(&mut self, identifier: Identifier, value: Value) { - self.is_garbage_collected = false; + log::trace!("Setting {identifier} to value {value}"); - self.variables.insert( - identifier, - (VariableData::Value(value), UsageData::default()), - ); + let mut variables = self.variables.write().unwrap(); + + let last_position = variables + .get(&identifier) + .map(|(_, last_position)| *last_position) + .unwrap_or_default(); + + variables.insert(identifier, (VariableData::Value(value), last_position)); } - pub fn collect_garbage(&mut self) { - if !self.is_garbage_collected { - self.variables - .retain(|_, (_, usage_data)| usage_data.used < usage_data.allowed_uses); - self.variables.shrink_to_fit(); + pub fn collect_garbage(&mut self, current_position: usize) { + log::trace!("Collecting garbage up to {current_position}"); + + let mut is_garbage_collected_to = self.is_garbage_collected_to.write().unwrap(); + + if current_position < *is_garbage_collected_to { + return; } + + let mut variables = self.variables.write().unwrap(); + + variables.retain(|identifier, (_, last_used)| { + let should_drop = current_position >= last_used.1; + + if should_drop { + log::trace!("Removing {identifier}"); + } + + !should_drop + }); + variables.shrink_to_fit(); + + *is_garbage_collected_to = current_position; } - pub fn add_allowed_use(&mut self, identifier: &Identifier) -> bool { - if let Some((_, usage_data)) = self.variables.get_mut(identifier) { - usage_data.allowed_uses += 1; + pub fn update_last_position(&mut self, identifier: &Identifier, position: Span) -> bool { + if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) { + *last_position = position; + + log::trace!("Updating {identifier}'s last position to {position:?}"); true } else { @@ -109,43 +126,16 @@ pub enum VariableData { Type(Type), } -#[derive(Debug, Clone)] -pub struct UsageData { - pub allowed_uses: u16, - pub used: u16, -} - -impl Default for UsageData { - fn default() -> Self { - Self { - allowed_uses: 1, - used: 0, - } - } -} - #[cfg(test)] mod tests { use crate::vm::run_with_context; use super::*; - #[test] - fn context_removes_unused_variables() { - let source = " - x = 5 - y = 10 - z = x + y - "; - let mut context = Context::new(); - - run_with_context(source, &mut context).unwrap(); - - assert_eq!(context.variables.len(), 1); - } - #[test] fn context_removes_used_variables() { + env_logger::builder().is_test(true).try_init().unwrap(); + let source = " x = 5 y = 10 @@ -156,41 +146,22 @@ mod tests { run_with_context(source, &mut context).unwrap(); - assert_eq!(context.variables.len(), 0); + assert_eq!(context.variable_count(), 0); } #[test] - fn context_does_not_remove_variables_during_loop() { + fn context_removes_variables_after_loop() { let source = " - x = 5 - y = 10 - z = x + y + y = 1 + z = 0 while z < 10 { - z = z + 1 + z = z + y } "; let mut context = Context::new(); run_with_context(source, &mut context).unwrap(); - assert_eq!(context.variables.len(), 1); - } - - #[test] - fn context_removes_variables_after_loop() { - let source = " - x = 5 - y = 10 - z = x + y - while z < 10 { - z = z + 1 - } - z - "; - let mut context = Context::new(); - - run_with_context(source, &mut context).unwrap(); - - assert_eq!(context.variables.len(), 0); + assert_eq!(context.variable_count(), 0); } } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 3d8a084..e84af21 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -17,7 +17,7 @@ pub mod vm; pub use abstract_tree::{AbstractSyntaxTree, BinaryOperator, Node, Statement}; pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; -pub use context::{Context, UsageData, VariableData}; +pub use context::{Context, VariableData}; pub use dust_error::DustError; pub use identifier::Identifier; pub use lexer::{lex, LexError, Lexer}; diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 49639cc..768d3bd 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -11,21 +11,9 @@ use crate::{ }; pub fn run(source: &str) -> Result, DustError> { - let abstract_syntax_tree = parse(source)?; let mut context = Context::new(); - let mut analyzer = Analyzer::new(&abstract_syntax_tree, &mut context); - analyzer - .analyze() - .map_err(|analyzer_error| DustError::AnalyzerError { - analyzer_error, - source, - })?; - - let mut vm = Vm::new(abstract_syntax_tree); - - vm.run(&mut context) - .map_err(|vm_error| DustError::VmError { vm_error, source }) + run_with_context(source, &mut context) } pub fn run_with_context<'src>( @@ -58,14 +46,21 @@ impl Vm { } pub fn run(&mut self, context: &mut Context) -> Result, VmError> { + let mut previous_position = (0, 0); let mut previous_value = None; while let Some(statement) = self.abstract_tree.nodes.pop_front() { - previous_value = self.run_statement(statement, context, true)?; + let new_position = statement.position; - context.collect_garbage(); + previous_value = self.run_statement(statement, context)?; + + context.collect_garbage(previous_position.1); + + previous_position = new_position; } + context.collect_garbage(previous_position.1); + Ok(previous_value) } @@ -73,7 +68,6 @@ impl Vm { &self, node: Node, context: &mut Context, - collect_garbage: bool, ) -> Result, VmError> { match node.inner { Statement::BinaryOperation { @@ -91,10 +85,7 @@ impl Vm { position: left.position, }); }; - - let value = if let Some(value) = - self.run_statement(*right, context, collect_garbage)? - { + let value = if let Some(value) = self.run_statement(*right, context)? { value } else { return Err(VmError::ExpectedValue { @@ -108,30 +99,30 @@ impl Vm { } if let BinaryOperator::AddAssign = operator.inner { - let identifier = if let Statement::Identifier(identifier) = left.inner { - identifier - } else { - return Err(VmError::ExpectedIdentifier { - position: left.position, - }); - }; - let right_value = if let Some(value) = - self.run_statement(*right, context, collect_garbage)? - { + let (identifier, left_value) = + if let Statement::Identifier(identifier) = left.inner { + let value = context.get_value(&identifier).ok_or_else(|| { + VmError::UndefinedVariable { + identifier: Node::new( + Statement::Identifier(identifier.clone()), + left.position, + ), + } + })?; + + (identifier, value) + } else { + return Err(VmError::ExpectedIdentifier { + position: left.position, + }); + }; + let right_value = if let Some(value) = self.run_statement(*right, context)? { value } else { return Err(VmError::ExpectedValue { position: right_position, }); }; - let left_value = context.use_value(&identifier).ok_or_else(|| { - VmError::UndefinedVariable { - identifier: Node::new( - Statement::Identifier(identifier.clone()), - left.position, - ), - } - })?; let new_value = left_value.add(&right_value).map_err(|value_error| { VmError::ValueError { error: value_error, @@ -145,22 +136,20 @@ impl Vm { } let left_position = left.position; - let left_value = - if let Some(value) = self.run_statement(*left, context, collect_garbage)? { - value - } else { - return Err(VmError::ExpectedValue { - position: left_position, - }); - }; - let right_value = - if let Some(value) = self.run_statement(*right, context, collect_garbage)? { - value - } else { - return Err(VmError::ExpectedValue { - position: right_position, - }); - }; + let left_value = if let Some(value) = self.run_statement(*left, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: left_position, + }); + }; + let right_value = if let Some(value) = self.run_statement(*right, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: right_position, + }); + }; match operator.inner { BinaryOperator::Add => left_value.add(&right_value), @@ -189,7 +178,7 @@ impl Vm { let mut previous_value = None; for statement in statements { - previous_value = self.run_statement(statement, context, collect_garbage)?; + previous_value = self.run_statement(statement, context)?; } Ok(previous_value) @@ -204,9 +193,7 @@ impl Vm { for node in nodes { let position = node.position; - let value = if let Some(value) = - self.run_statement(node, context, collect_garbage)? - { + let value = if let Some(value) = self.run_statement(node, context)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -236,15 +223,14 @@ impl Vm { value_arguments: value_parameter_nodes, } => { let function_position = function_node.position; - let function_value = if let Some(value) = - self.run_statement(*function_node, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: function_position, - }); - }; + let function_value = + if let Some(value) = self.run_statement(*function_node, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: function_position, + }); + }; let function = if let Some(function) = function_value.as_function() { function } else { @@ -259,9 +245,7 @@ impl Vm { for node in value_nodes { let position = node.position; - let value = if let Some(value) = - self.run_statement(node, context, collect_garbage)? - { + let value = if let Some(value) = self.run_statement(node, context)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -278,11 +262,7 @@ impl Vm { Ok(function.clone().call(None, value_parameters, context)?) } Statement::Identifier(identifier) => { - let value_option = if collect_garbage { - context.use_value(&identifier) - } else { - context.get_value(&identifier) - }; + let value_option = context.get_value(&identifier); if let Some(value) = value_option { Ok(Some(value.clone())) @@ -294,15 +274,14 @@ impl Vm { } Statement::If { condition, body } => { let condition_position = condition.position; - let condition_value = if let Some(value) = - self.run_statement(*condition, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: condition_position, - }); - }; + let condition_value = + if let Some(value) = self.run_statement(*condition, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; let condition = if let Some(condition) = condition_value.as_boolean() { condition } else { @@ -312,7 +291,7 @@ impl Vm { }; if condition { - self.run_statement(*body, context, collect_garbage)?; + self.run_statement(*body, context)?; } Ok(None) @@ -323,21 +302,20 @@ impl Vm { else_body, } => { let condition_position = condition.position; - let condition_value = if let Some(value) = - self.run_statement(*condition, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: condition_position, - }); - }; + let condition_value = + if let Some(value) = self.run_statement(*condition, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; if let Some(condition) = condition_value.as_boolean() { if condition { - self.run_statement(*if_body, context, collect_garbage) + self.run_statement(*if_body, context) } else { - self.run_statement(*else_body, context, collect_garbage) + self.run_statement(*else_body, context) } } else { Err(VmError::ExpectedBoolean { @@ -351,31 +329,29 @@ impl Vm { else_ifs, } => { let condition_position = condition.position; - let condition_value = if let Some(value) = - self.run_statement(*condition, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: condition_position, - }); - }; + let condition_value = + if let Some(value) = self.run_statement(*condition, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; if let Some(condition) = condition_value.as_boolean() { if condition { - self.run_statement(*if_body, context, collect_garbage) + self.run_statement(*if_body, context) } else { for (condition, body) in else_ifs { let condition_position = condition.position; - let condition_value = if let Some(value) = - self.run_statement(condition, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: condition_position, - }); - }; + let condition_value = + if let Some(value) = self.run_statement(condition, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; let condition = if let Some(condition) = condition_value.as_boolean() { condition } else { @@ -385,7 +361,7 @@ impl Vm { }; if condition { - self.run_statement(body, context, collect_garbage)?; + self.run_statement(body, context)?; } } @@ -404,31 +380,29 @@ impl Vm { else_body, } => { let condition_position = condition.position; - let condition_value = if let Some(value) = - self.run_statement(*condition, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: condition_position, - }); - }; + let condition_value = + if let Some(value) = self.run_statement(*condition, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; if let Some(condition) = condition_value.as_boolean() { if condition { - self.run_statement(*if_body, context, collect_garbage) + self.run_statement(*if_body, context) } else { for (condition, body) in else_ifs { let condition_position = condition.position; - let condition_value = if let Some(value) = - self.run_statement(condition, context, collect_garbage)? - { - value - } else { - return Err(VmError::ExpectedValue { - position: condition_position, - }); - }; + let condition_value = + if let Some(value) = self.run_statement(condition, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; let condition = if let Some(condition) = condition_value.as_boolean() { condition } else { @@ -438,11 +412,11 @@ impl Vm { }; if condition { - return self.run_statement(body, context, collect_garbage); + return self.run_statement(body, context); } } - self.run_statement(*else_body, context, collect_garbage) + self.run_statement(*else_body, context) } } else { Err(VmError::ExpectedBoolean { @@ -455,7 +429,7 @@ impl Vm { .into_iter() .map(|node| { let span = node.position; - if let Some(value) = self.run_statement(node, context, collect_garbage)? { + if let Some(value) = self.run_statement(node, context)? { Ok(value) } else { Err(VmError::ExpectedValue { position: span }) @@ -477,9 +451,7 @@ impl Vm { }); }; let position = value_node.position; - let value = if let Some(value) = - self.run_statement(value_node, context, collect_garbage)? - { + let value = if let Some(value) = self.run_statement(value_node, context)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -491,20 +463,19 @@ impl Vm { Ok(Some(Value::map(values))) } Statement::Nil(node) => { - let _return = self.run_statement(*node, context, collect_garbage)?; + let _return = self.run_statement(*node, context)?; Ok(None) } Statement::PropertyAccess(left, right) => { let left_span = left.position; - let left_value = - if let Some(value) = self.run_statement(*left, context, collect_garbage)? { - value - } else { - return Err(VmError::ExpectedValue { - position: left_span, - }); - }; + let left_value = if let Some(value) = self.run_statement(*left, context)? { + value + } else { + return Err(VmError::ExpectedValue { + position: left_span, + }); + }; let right_span = right.position; if let (Some(list), Statement::Constant(value)) = @@ -534,9 +505,7 @@ impl Vm { let condition_position = condition.position; - while let Some(condition_value) = - self.run_statement(*condition.clone(), context, false)? - { + while let Some(condition_value) = self.run_statement(*condition.clone(), context)? { if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() { if !condition_value { break; @@ -547,7 +516,7 @@ impl Vm { }); } - return_value = self.run_statement(*body.clone(), context, false)?; + return_value = self.run_statement(*body.clone(), context)?; if return_value.is_some() { break;