Work out the finer details of the garbage collector

This commit is contained in:
Jeff 2024-08-12 04:10:07 -04:00
parent 0e3a3e94c8
commit 74cfef1832
7 changed files with 249 additions and 304 deletions

9
Cargo.lock generated
View File

@ -152,6 +152,7 @@ version = "0.5.0"
dependencies = [ dependencies = [
"annotate-snippets", "annotate-snippets",
"env_logger", "env_logger",
"log",
"rand", "rand",
"rayon", "rayon",
"serde", "serde",
@ -184,9 +185,9 @@ dependencies = [
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.11.3" version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -232,9 +233,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.21" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "memchr" name = "memchr"

View File

@ -11,7 +11,11 @@ repository.workspace = true
[dependencies] [dependencies]
annotate-snippets = "0.11.4" annotate-snippets = "0.11.4"
env_logger = "0.11.3" env_logger = "0.11.3"
log = "0.4.22"
rand = "0.8.5" rand = "0.8.5"
rayon = "1.9.0" rayon = "1.9.0"
serde = { version = "1.0.203", features = ["derive"] } serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.117" serde_json = "1.0.117"
[dev-dependencies]
env_logger = "0.11.5"

View File

@ -127,7 +127,7 @@ impl Statement {
Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(), Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(),
Statement::Constant(value) => Some(value.r#type(context)), Statement::Constant(value) => Some(value.r#type(context)),
Statement::FunctionCall { function, .. } => function.inner.expected_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::If { .. } => None,
Statement::IfElse { if_body, .. } => if_body.inner.expected_type(context), Statement::IfElse { if_body, .. } => if_body.inner.expected_type(context),
Statement::IfElseIf { .. } => None, Statement::IfElseIf { .. } => None,

View File

@ -67,38 +67,38 @@ impl<'a> Analyzer<'a> {
pub fn analyze(&mut self) -> Result<(), AnalyzerError> { pub fn analyze(&mut self) -> Result<(), AnalyzerError> {
for node in &self.abstract_tree.nodes { for node in &self.abstract_tree.nodes {
self.analyze_node(node)?; self.analyze_statement(node)?;
} }
Ok(()) Ok(())
} }
fn analyze_node(&mut self, node: &Node<Statement>) -> Result<(), AnalyzerError> { fn analyze_statement(&mut self, node: &Node<Statement>) -> Result<(), AnalyzerError> {
match &node.inner { match &node.inner {
Statement::BinaryOperation { Statement::BinaryOperation {
left, left,
operator, operator,
right, 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 { if let Statement::Identifier(identifier) = &left.inner {
self.analyze_node(right)?; let right_type = right.inner.expected_type(self.context).ok_or(
AnalyzerError::ExpectedValue {
let right_type = right.inner.expected_type(self.context);
self.context.set_type(
identifier.clone(),
right_type.ok_or(AnalyzerError::ExpectedValue {
actual: right.as_ref().clone(), actual: right.as_ref().clone(),
})?, },
); )?;
self.context
.set_type(identifier.clone(), right_type, left.position);
return Ok(()); return Ok(());
} }
} }
self.analyze_node(left)?; self.analyze_statement(left)?;
self.analyze_node(right)?; self.analyze_statement(right)?;
let left_type = left.inner.expected_type(self.context); let left_type = left.inner.expected_type(self.context);
let right_type = right.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) => { Statement::Block(statements) => {
for statement in statements { for statement in statements {
self.analyze_node(statement)?; self.analyze_statement(statement)?;
} }
} }
Statement::BuiltInFunctionCall { Statement::BuiltInFunctionCall {
@ -143,7 +143,7 @@ impl<'a> Analyzer<'a> {
if let Some(arguments) = value_arguments { if let Some(arguments) = value_arguments {
for argument in arguments { for argument in arguments {
self.analyze_node(argument)?; self.analyze_statement(argument)?;
} }
if arguments.len() != value_parameters.len() { if arguments.len() != value_parameters.len() {
@ -195,16 +195,16 @@ impl<'a> Analyzer<'a> {
value_arguments, value_arguments,
.. ..
} => { } => {
self.analyze_node(function)?; self.analyze_statement(function)?;
if let Some(arguments) = value_arguments { if let Some(arguments) = value_arguments {
for argument in arguments { for argument in arguments {
self.analyze_node(argument)?; self.analyze_statement(argument)?;
} }
} }
} }
Statement::Identifier(identifier) => { Statement::Identifier(identifier) => {
let exists = self.context.add_allowed_use(identifier); let exists = self.context.update_last_position(identifier, node.position);
if !exists { if !exists {
return Err(AnalyzerError::UndefinedVariable { return Err(AnalyzerError::UndefinedVariable {
@ -213,7 +213,7 @@ impl<'a> Analyzer<'a> {
} }
} }
Statement::If { condition, body } => { Statement::If { condition, body } => {
self.analyze_node(condition)?; self.analyze_statement(condition)?;
if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
// Condition is valid // Condition is valid
@ -223,14 +223,14 @@ impl<'a> Analyzer<'a> {
}); });
} }
self.analyze_node(body)?; self.analyze_statement(body)?;
} }
Statement::IfElse { Statement::IfElse {
condition, condition,
if_body, if_body,
else_body, else_body,
} => { } => {
self.analyze_node(condition)?; self.analyze_statement(condition)?;
if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
// Condition is valid // Condition is valid
@ -240,15 +240,15 @@ impl<'a> Analyzer<'a> {
}); });
} }
self.analyze_node(if_body)?; self.analyze_statement(if_body)?;
self.analyze_node(else_body)?; self.analyze_statement(else_body)?;
} }
Statement::IfElseIf { Statement::IfElseIf {
condition, condition,
if_body, if_body,
else_ifs, else_ifs,
} => { } => {
self.analyze_node(condition)?; self.analyze_statement(condition)?;
if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
// Condition is valid // 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 { 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) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
// Condition is valid // Condition is valid
@ -271,7 +271,7 @@ impl<'a> Analyzer<'a> {
}); });
} }
self.analyze_node(body)?; self.analyze_statement(body)?;
} }
} }
Statement::IfElseIfElse { Statement::IfElseIfElse {
@ -280,7 +280,7 @@ impl<'a> Analyzer<'a> {
else_ifs, else_ifs,
else_body, else_body,
} => { } => {
self.analyze_node(condition)?; self.analyze_statement(condition)?;
if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
// Condition is valid // 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 { 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) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
// Condition is valid // 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) => { Statement::List(statements) => {
for statement in statements { for statement in statements {
self.analyze_node(statement)?; self.analyze_statement(statement)?;
} }
} }
Statement::Map(properties) => { Statement::Map(properties) => {
for (_key, value_node) in properties { for (_key, value_node) in properties {
self.analyze_node(value_node)?; self.analyze_statement(value_node)?;
} }
} }
Statement::Nil(node) => { Statement::Nil(node) => {
self.analyze_node(node)?; self.analyze_statement(node)?;
} }
Statement::PropertyAccess(left, right) => { Statement::PropertyAccess(left, right) => {
self.analyze_node(left)?; self.analyze_statement(left)?;
if let Statement::Identifier(_) = right.inner { if let Statement::Identifier(_) = right.inner {
// Do not expect a value for property accessors // Do not expect a value for property accessors
} else { } else {
self.analyze_node(right)?; self.analyze_statement(right)?;
} }
if let Some(Type::List { .. }) = left.inner.expected_type(self.context) { if let Some(Type::List { .. }) = left.inner.expected_type(self.context) {
@ -353,8 +353,8 @@ impl<'a> Analyzer<'a> {
} }
} }
Statement::While { condition, body } => { Statement::While { condition, body } => {
self.analyze_node(condition)?; self.analyze_statement(condition)?;
self.analyze_node(body)?; self.analyze_statement(body)?;
if let Some(Type::Boolean) = condition.inner.expected_type(self.context) { if let Some(Type::Boolean) = condition.inner.expected_type(self.context) {
} else { } else {

View File

@ -1,94 +1,111 @@
//! Garbage-collecting context for variables. //! 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. /// Garbage-collecting context for variables.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Context { pub struct Context {
variables: HashMap<Identifier, (VariableData, UsageData)>, variables: Arc<RwLock<HashMap<Identifier, (VariableData, Span)>>>,
is_garbage_collected: bool, is_garbage_collected_to: Arc<RwLock<usize>>,
} }
impl Context { impl Context {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
variables: HashMap::new(), variables: Arc::new(RwLock::new(HashMap::new())),
is_garbage_collected: true, 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 { 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)> { pub fn get(&self, identifier: &Identifier) -> Option<(VariableData, Span)> {
self.variables.get(identifier) self.variables.read().unwrap().get(identifier).cloned()
} }
pub fn get_type(&self, identifier: &Identifier) -> Option<&Type> { pub fn get_type(&self, identifier: &Identifier) -> Option<Type> {
match self.variables.get(identifier) { match self.variables.read().unwrap().get(identifier) {
Some((VariableData::Type(r#type), _)) => Some(r#type), Some((VariableData::Type(r#type), _)) => Some(r#type.clone()),
_ => None, _ => None,
} }
} }
pub fn get_variable_data(&self, identifier: &Identifier) -> Option<&VariableData> { pub fn get_variable_data(&self, identifier: &Identifier) -> Option<VariableData> {
match self.variables.get(identifier) { match self.variables.read().unwrap().get(identifier) {
Some((variable_data, _)) => Some(variable_data), Some((variable_data, _)) => Some(variable_data.clone()),
_ => None, _ => None,
} }
} }
pub fn get_value(&self, identifier: &Identifier) -> Option<&Value> { pub fn get_value(&self, identifier: &Identifier) -> Option<Value> {
match self.variables.get(identifier) { match self.variables.read().unwrap().get(identifier) {
Some((VariableData::Value(value), _)) => Some(value), Some((VariableData::Value(value), _)) => Some(value.clone()),
_ => None, _ => None,
} }
} }
pub fn use_value(&mut self, identifier: &Identifier) -> Option<&Value> { pub fn set_type(&mut self, identifier: Identifier, r#type: Type, position: Span) {
self.is_garbage_collected = false; log::trace!("Setting {identifier} to type {type} at {position:?}");
match self.variables.get_mut(identifier) { self.variables
Some((VariableData::Value(value), usage_data)) => { .write()
usage_data.used += 1; .unwrap()
.insert(identifier, (VariableData::Type(r#type), position));
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()),
);
} }
pub fn set_value(&mut self, identifier: Identifier, value: Value) { 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( let mut variables = self.variables.write().unwrap();
identifier,
(VariableData::Value(value), UsageData::default()), 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) { pub fn collect_garbage(&mut self, current_position: usize) {
if !self.is_garbage_collected { log::trace!("Collecting garbage up to {current_position}");
self.variables
.retain(|_, (_, usage_data)| usage_data.used < usage_data.allowed_uses); let mut is_garbage_collected_to = self.is_garbage_collected_to.write().unwrap();
self.variables.shrink_to_fit();
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 { pub fn update_last_position(&mut self, identifier: &Identifier, position: Span) -> bool {
if let Some((_, usage_data)) = self.variables.get_mut(identifier) { if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) {
usage_data.allowed_uses += 1; *last_position = position;
log::trace!("Updating {identifier}'s last position to {position:?}");
true true
} else { } else {
@ -109,43 +126,16 @@ pub enum VariableData {
Type(Type), 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)] #[cfg(test)]
mod tests { mod tests {
use crate::vm::run_with_context; use crate::vm::run_with_context;
use super::*; 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] #[test]
fn context_removes_used_variables() { fn context_removes_used_variables() {
env_logger::builder().is_test(true).try_init().unwrap();
let source = " let source = "
x = 5 x = 5
y = 10 y = 10
@ -156,41 +146,22 @@ mod tests {
run_with_context(source, &mut context).unwrap(); run_with_context(source, &mut context).unwrap();
assert_eq!(context.variables.len(), 0); assert_eq!(context.variable_count(), 0);
} }
#[test] #[test]
fn context_does_not_remove_variables_during_loop() { fn context_removes_variables_after_loop() {
let source = " let source = "
x = 5 y = 1
y = 10 z = 0
z = x + y
while z < 10 { while z < 10 {
z = z + 1 z = z + y
} }
"; ";
let mut context = Context::new(); let mut context = Context::new();
run_with_context(source, &mut context).unwrap(); run_with_context(source, &mut context).unwrap();
assert_eq!(context.variables.len(), 1); assert_eq!(context.variable_count(), 0);
}
#[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);
} }
} }

View File

@ -17,7 +17,7 @@ pub mod vm;
pub use abstract_tree::{AbstractSyntaxTree, BinaryOperator, Node, Statement}; pub use abstract_tree::{AbstractSyntaxTree, BinaryOperator, Node, Statement};
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; 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 dust_error::DustError;
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lexer::{lex, LexError, Lexer}; pub use lexer::{lex, LexError, Lexer};

View File

@ -11,21 +11,9 @@ use crate::{
}; };
pub fn run(source: &str) -> Result<Option<Value>, DustError> { pub fn run(source: &str) -> Result<Option<Value>, DustError> {
let abstract_syntax_tree = parse(source)?;
let mut context = Context::new(); let mut context = Context::new();
let mut analyzer = Analyzer::new(&abstract_syntax_tree, &mut context);
analyzer run_with_context(source, &mut context)
.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 })
} }
pub fn run_with_context<'src>( pub fn run_with_context<'src>(
@ -58,14 +46,21 @@ impl Vm {
} }
pub fn run(&mut self, context: &mut Context) -> Result<Option<Value>, VmError> { pub fn run(&mut self, context: &mut Context) -> Result<Option<Value>, VmError> {
let mut previous_position = (0, 0);
let mut previous_value = None; let mut previous_value = None;
while let Some(statement) = self.abstract_tree.nodes.pop_front() { 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) Ok(previous_value)
} }
@ -73,7 +68,6 @@ impl Vm {
&self, &self,
node: Node<Statement>, node: Node<Statement>,
context: &mut Context, context: &mut Context,
collect_garbage: bool,
) -> Result<Option<Value>, VmError> { ) -> Result<Option<Value>, VmError> {
match node.inner { match node.inner {
Statement::BinaryOperation { Statement::BinaryOperation {
@ -91,10 +85,7 @@ impl Vm {
position: left.position, position: left.position,
}); });
}; };
let value = if let Some(value) = self.run_statement(*right, context)? {
let value = if let Some(value) =
self.run_statement(*right, context, collect_garbage)?
{
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
@ -108,30 +99,30 @@ impl Vm {
} }
if let BinaryOperator::AddAssign = operator.inner { if let BinaryOperator::AddAssign = operator.inner {
let identifier = if let Statement::Identifier(identifier) = left.inner { let (identifier, left_value) =
identifier if let Statement::Identifier(identifier) = left.inner {
} else { let value = context.get_value(&identifier).ok_or_else(|| {
return Err(VmError::ExpectedIdentifier { VmError::UndefinedVariable {
position: left.position, identifier: Node::new(
}); Statement::Identifier(identifier.clone()),
}; left.position,
let right_value = if let Some(value) = ),
self.run_statement(*right, context, collect_garbage)? }
{ })?;
(identifier, value)
} else {
return Err(VmError::ExpectedIdentifier {
position: left.position,
});
};
let right_value = if let Some(value) = self.run_statement(*right, context)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
position: right_position, 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| { let new_value = left_value.add(&right_value).map_err(|value_error| {
VmError::ValueError { VmError::ValueError {
error: value_error, error: value_error,
@ -145,22 +136,20 @@ impl Vm {
} }
let left_position = left.position; let left_position = left.position;
let left_value = let left_value = if let Some(value) = self.run_statement(*left, context)? {
if let Some(value) = self.run_statement(*left, context, collect_garbage)? { value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: left_position,
position: left_position, });
}); };
}; let right_value = if let Some(value) = self.run_statement(*right, context)? {
let right_value = value
if let Some(value) = self.run_statement(*right, context, collect_garbage)? { } else {
value return Err(VmError::ExpectedValue {
} else { position: right_position,
return Err(VmError::ExpectedValue { });
position: right_position, };
});
};
match operator.inner { match operator.inner {
BinaryOperator::Add => left_value.add(&right_value), BinaryOperator::Add => left_value.add(&right_value),
@ -189,7 +178,7 @@ impl Vm {
let mut previous_value = None; let mut previous_value = None;
for statement in statements { for statement in statements {
previous_value = self.run_statement(statement, context, collect_garbage)?; previous_value = self.run_statement(statement, context)?;
} }
Ok(previous_value) Ok(previous_value)
@ -204,9 +193,7 @@ impl Vm {
for node in nodes { for node in nodes {
let position = node.position; let position = node.position;
let value = if let Some(value) = let value = if let Some(value) = self.run_statement(node, context)? {
self.run_statement(node, context, collect_garbage)?
{
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -236,15 +223,14 @@ impl Vm {
value_arguments: value_parameter_nodes, value_arguments: value_parameter_nodes,
} => { } => {
let function_position = function_node.position; let function_position = function_node.position;
let function_value = if let Some(value) = let function_value =
self.run_statement(*function_node, context, collect_garbage)? if let Some(value) = self.run_statement(*function_node, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: function_position,
position: function_position, });
}); };
};
let function = if let Some(function) = function_value.as_function() { let function = if let Some(function) = function_value.as_function() {
function function
} else { } else {
@ -259,9 +245,7 @@ impl Vm {
for node in value_nodes { for node in value_nodes {
let position = node.position; let position = node.position;
let value = if let Some(value) = let value = if let Some(value) = self.run_statement(node, context)? {
self.run_statement(node, context, collect_garbage)?
{
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -278,11 +262,7 @@ impl Vm {
Ok(function.clone().call(None, value_parameters, context)?) Ok(function.clone().call(None, value_parameters, context)?)
} }
Statement::Identifier(identifier) => { Statement::Identifier(identifier) => {
let value_option = if collect_garbage { let value_option = context.get_value(&identifier);
context.use_value(&identifier)
} else {
context.get_value(&identifier)
};
if let Some(value) = value_option { if let Some(value) = value_option {
Ok(Some(value.clone())) Ok(Some(value.clone()))
@ -294,15 +274,14 @@ impl Vm {
} }
Statement::If { condition, body } => { Statement::If { condition, body } => {
let condition_position = condition.position; let condition_position = condition.position;
let condition_value = if let Some(value) = let condition_value =
self.run_statement(*condition, context, collect_garbage)? if let Some(value) = self.run_statement(*condition, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: condition_position,
position: condition_position, });
}); };
};
let condition = if let Some(condition) = condition_value.as_boolean() { let condition = if let Some(condition) = condition_value.as_boolean() {
condition condition
} else { } else {
@ -312,7 +291,7 @@ impl Vm {
}; };
if condition { if condition {
self.run_statement(*body, context, collect_garbage)?; self.run_statement(*body, context)?;
} }
Ok(None) Ok(None)
@ -323,21 +302,20 @@ impl Vm {
else_body, else_body,
} => { } => {
let condition_position = condition.position; let condition_position = condition.position;
let condition_value = if let Some(value) = let condition_value =
self.run_statement(*condition, context, collect_garbage)? if let Some(value) = self.run_statement(*condition, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: condition_position,
position: condition_position, });
}); };
};
if let Some(condition) = condition_value.as_boolean() { if let Some(condition) = condition_value.as_boolean() {
if condition { if condition {
self.run_statement(*if_body, context, collect_garbage) self.run_statement(*if_body, context)
} else { } else {
self.run_statement(*else_body, context, collect_garbage) self.run_statement(*else_body, context)
} }
} else { } else {
Err(VmError::ExpectedBoolean { Err(VmError::ExpectedBoolean {
@ -351,31 +329,29 @@ impl Vm {
else_ifs, else_ifs,
} => { } => {
let condition_position = condition.position; let condition_position = condition.position;
let condition_value = if let Some(value) = let condition_value =
self.run_statement(*condition, context, collect_garbage)? if let Some(value) = self.run_statement(*condition, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: condition_position,
position: condition_position, });
}); };
};
if let Some(condition) = condition_value.as_boolean() { if let Some(condition) = condition_value.as_boolean() {
if condition { if condition {
self.run_statement(*if_body, context, collect_garbage) self.run_statement(*if_body, context)
} else { } else {
for (condition, body) in else_ifs { for (condition, body) in else_ifs {
let condition_position = condition.position; let condition_position = condition.position;
let condition_value = if let Some(value) = let condition_value =
self.run_statement(condition, context, collect_garbage)? if let Some(value) = self.run_statement(condition, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: condition_position,
position: condition_position, });
}); };
};
let condition = if let Some(condition) = condition_value.as_boolean() { let condition = if let Some(condition) = condition_value.as_boolean() {
condition condition
} else { } else {
@ -385,7 +361,7 @@ impl Vm {
}; };
if condition { if condition {
self.run_statement(body, context, collect_garbage)?; self.run_statement(body, context)?;
} }
} }
@ -404,31 +380,29 @@ impl Vm {
else_body, else_body,
} => { } => {
let condition_position = condition.position; let condition_position = condition.position;
let condition_value = if let Some(value) = let condition_value =
self.run_statement(*condition, context, collect_garbage)? if let Some(value) = self.run_statement(*condition, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: condition_position,
position: condition_position, });
}); };
};
if let Some(condition) = condition_value.as_boolean() { if let Some(condition) = condition_value.as_boolean() {
if condition { if condition {
self.run_statement(*if_body, context, collect_garbage) self.run_statement(*if_body, context)
} else { } else {
for (condition, body) in else_ifs { for (condition, body) in else_ifs {
let condition_position = condition.position; let condition_position = condition.position;
let condition_value = if let Some(value) = let condition_value =
self.run_statement(condition, context, collect_garbage)? if let Some(value) = self.run_statement(condition, context)? {
{ value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: condition_position,
position: condition_position, });
}); };
};
let condition = if let Some(condition) = condition_value.as_boolean() { let condition = if let Some(condition) = condition_value.as_boolean() {
condition condition
} else { } else {
@ -438,11 +412,11 @@ impl Vm {
}; };
if condition { 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 { } else {
Err(VmError::ExpectedBoolean { Err(VmError::ExpectedBoolean {
@ -455,7 +429,7 @@ impl Vm {
.into_iter() .into_iter()
.map(|node| { .map(|node| {
let span = node.position; 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) Ok(value)
} else { } else {
Err(VmError::ExpectedValue { position: span }) Err(VmError::ExpectedValue { position: span })
@ -477,9 +451,7 @@ impl Vm {
}); });
}; };
let position = value_node.position; let position = value_node.position;
let value = if let Some(value) = let value = if let Some(value) = self.run_statement(value_node, context)? {
self.run_statement(value_node, context, collect_garbage)?
{
value value
} else { } else {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
@ -491,20 +463,19 @@ impl Vm {
Ok(Some(Value::map(values))) Ok(Some(Value::map(values)))
} }
Statement::Nil(node) => { Statement::Nil(node) => {
let _return = self.run_statement(*node, context, collect_garbage)?; let _return = self.run_statement(*node, context)?;
Ok(None) Ok(None)
} }
Statement::PropertyAccess(left, right) => { Statement::PropertyAccess(left, right) => {
let left_span = left.position; let left_span = left.position;
let left_value = let left_value = if let Some(value) = self.run_statement(*left, context)? {
if let Some(value) = self.run_statement(*left, context, collect_garbage)? { value
value } else {
} else { return Err(VmError::ExpectedValue {
return Err(VmError::ExpectedValue { position: left_span,
position: left_span, });
}); };
};
let right_span = right.position; let right_span = right.position;
if let (Some(list), Statement::Constant(value)) = if let (Some(list), Statement::Constant(value)) =
@ -534,9 +505,7 @@ impl Vm {
let condition_position = condition.position; let condition_position = condition.position;
while let Some(condition_value) = while let Some(condition_value) = self.run_statement(*condition.clone(), context)? {
self.run_statement(*condition.clone(), context, false)?
{
if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() { if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() {
if !condition_value { if !condition_value {
break; 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() { if return_value.is_some() {
break; break;