From c71c4d2d073150c730fe2cdc4184f0dffd70d6b4 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Aug 2024 08:54:21 -0400 Subject: [PATCH] Refactor VM to own its context --- dust-lang/src/analyzer.rs | 15 ++-- dust-lang/src/context.rs | 25 ++++-- dust-lang/src/value.rs | 8 +- dust-lang/src/vm.rs | 183 +++++++++++++++++++------------------- 4 files changed, 119 insertions(+), 112 deletions(-) diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index b5bdd91..daf0e94 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -1,10 +1,9 @@ //! Tools for analyzing an abstract syntax tree and catch errors before running the virtual //! machine. //! -//! This module provides to anlysis options, both of which borrow an abstract syntax tree and a -//! hash map of variables: -//! - `analyze` convenience function -//! - `Analyzer` struct +//! This module provides two anlysis options: +//! - `analyze` convenience function, which takes a string input +//! - `Analyzer` struct, which borrows an abstract syntax tree and a context use std::{ error::Error, fmt::{self, Display, Formatter}, @@ -28,8 +27,8 @@ use crate::{ /// ``` pub fn analyze(source: &str) -> Result<(), DustError> { let abstract_tree = parse(source)?; - let mut context = Context::new(); - let mut analyzer = Analyzer::new(&abstract_tree, &mut context); + let context = Context::new(); + let mut analyzer = Analyzer::new(&abstract_tree, &context); analyzer .analyze() @@ -54,11 +53,11 @@ pub fn analyze(source: &str) -> Result<(), DustError> { /// assert!(result.is_err()); pub struct Analyzer<'a> { abstract_tree: &'a AbstractSyntaxTree, - context: &'a mut Context, + context: &'a Context, } impl<'a> Analyzer<'a> { - pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: &'a mut Context) -> Self { + pub fn new(abstract_tree: &'a AbstractSyntaxTree, context: &'a Context) -> Self { Self { abstract_tree, context, diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index 2b34550..13368fa 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -21,6 +21,15 @@ impl Context { } } + pub fn with_variables_from(other: &Self) -> Self { + Self { + variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())), + is_garbage_collected_to: Arc::new(RwLock::new( + *other.is_garbage_collected_to.read().unwrap(), + )), + } + } + pub fn variable_count(&self) -> usize { self.variables.read().unwrap().len() } @@ -54,7 +63,7 @@ impl Context { } } - pub fn set_type(&mut self, identifier: Identifier, r#type: Type, position: Span) { + pub fn set_type(&self, identifier: Identifier, r#type: Type, position: Span) { log::trace!("Setting {identifier} to type {type} at {position:?}"); self.variables @@ -63,7 +72,7 @@ impl Context { .insert(identifier, (VariableData::Type(r#type), position)); } - pub fn set_value(&mut self, identifier: Identifier, value: Value) { + pub fn set_value(&self, identifier: Identifier, value: Value) { log::trace!("Setting {identifier} to value {value}"); let mut variables = self.variables.write().unwrap(); @@ -76,7 +85,7 @@ impl Context { variables.insert(identifier, (VariableData::Value(value), last_position)); } - pub fn collect_garbage(&mut self, current_position: usize) { + pub fn collect_garbage(&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(); @@ -101,7 +110,7 @@ impl Context { *is_garbage_collected_to = current_position; } - pub fn update_last_position(&mut self, identifier: &Identifier, position: Span) -> bool { + pub fn update_last_position(&self, identifier: &Identifier, position: Span) -> bool { if let Some((_, last_position)) = self.variables.write().unwrap().get_mut(identifier) { *last_position = position; @@ -142,9 +151,9 @@ mod tests { z = x + y z "; - let mut context = Context::new(); + let context = Context::new(); - run_with_context(source, &mut context).unwrap(); + run_with_context(source, context.clone()).unwrap(); assert_eq!(context.variable_count(), 0); } @@ -158,9 +167,9 @@ mod tests { z = z + y } "; - let mut context = Context::new(); + let context = Context::new(); - run_with_context(source, &mut context).unwrap(); + run_with_context(source, context.clone()).unwrap(); assert_eq!(context.variable_count(), 0); } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 07b3c5d..f80c6bf 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -748,9 +748,9 @@ impl Function { self, _type_arguments: Option>, value_arguments: Option>, - context: &mut Context, + context: &Context, ) -> Result, VmError> { - let mut new_context = context.clone(); + let new_context = Context::with_variables_from(context); if let (Some(value_parameters), Some(value_arguments)) = (self.value_parameters, value_arguments) @@ -760,9 +760,9 @@ impl Function { } } - let mut vm = Vm::new(self.body); + let mut vm = Vm::new(self.body, new_context); - vm.run(&mut new_context) + vm.run() } pub fn return_type(&self, variables: &Context) -> Option { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index b4075b3..52c7acd 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -1,27 +1,29 @@ //! Virtual machine for running the abstract syntax tree. +//! +//! This module provides three running option: +//! - `run` convenience function that takes a source code string and runs it +//! - `run_with_context` convenience function that takes a source code string and a context +//! - `Vm` struct that can be used to run an abstract syntax tree use std::{ collections::BTreeMap, fmt::{self, Display, Formatter}, }; use crate::{ - abstract_tree::BinaryOperator, parse, value::ValueInner, AbstractSyntaxTree, Analyzer, - BuiltInFunctionError, Context, DustError, Identifier, Node, ParseError, Span, Statement, - UnaryOperator, Value, ValueError, + parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError, + Context, DustError, Identifier, Node, ParseError, Span, Statement, UnaryOperator, Value, + ValueError, }; pub fn run(source: &str) -> Result, DustError> { - let mut context = Context::new(); + let context = Context::new(); - run_with_context(source, &mut context) + run_with_context(source, context) } -pub fn run_with_context<'src>( - source: &'src str, - context: &mut Context, -) -> Result, DustError<'src>> { +pub fn run_with_context(source: &str, context: Context) -> Result, DustError> { let abstract_syntax_tree = parse(source)?; - let mut analyzer = Analyzer::new(&abstract_syntax_tree, context); + let mut analyzer = Analyzer::new(&abstract_syntax_tree, &context); analyzer .analyze() @@ -30,45 +32,45 @@ pub fn run_with_context<'src>( source, })?; - let mut vm = Vm::new(abstract_syntax_tree); + let mut vm = Vm::new(abstract_syntax_tree, context); - vm.run(context) + vm.run() .map_err(|vm_error| DustError::VmError { vm_error, source }) } pub struct Vm { abstract_tree: AbstractSyntaxTree, + context: Context, } impl Vm { - pub fn new(abstract_tree: AbstractSyntaxTree) -> Self { - Self { abstract_tree } + pub fn new(abstract_tree: AbstractSyntaxTree, context: Context) -> Self { + Self { + abstract_tree, + context, + } } - pub fn run(&mut self, context: &mut Context) -> Result, VmError> { + pub fn run(&mut self) -> Result, VmError> { let mut previous_position = (0, 0); let mut previous_value = None; while let Some(statement) = self.abstract_tree.nodes.pop_front() { let new_position = statement.position; - previous_value = self.run_statement(statement, context)?; + previous_value = self.run_statement(statement)?; - context.collect_garbage(previous_position.1); + self.context.collect_garbage(previous_position.1); previous_position = new_position; } - context.collect_garbage(previous_position.1); + self.context.collect_garbage(previous_position.1); Ok(previous_value) } - fn run_statement( - &self, - node: Node, - context: &mut Context, - ) -> Result, VmError> { + fn run_statement(&self, node: Node) -> Result, VmError> { match node.inner { Statement::BinaryOperation { left, @@ -85,7 +87,7 @@ impl Vm { position: left.position, }); }; - let value = if let Some(value) = self.run_statement(*right, context)? { + let value = if let Some(value) = self.run_statement(*right)? { value } else { return Err(VmError::ExpectedValue { @@ -93,7 +95,7 @@ impl Vm { }); }; - context.set_value(identifier, value); + self.context.set_value(identifier, value); return Ok(None); } @@ -101,7 +103,7 @@ impl Vm { if let BinaryOperator::AddAssign = operator.inner { let (identifier, left_value) = if let Statement::Identifier(identifier) = left.inner { - let value = context.get_value(&identifier).ok_or_else(|| { + let value = self.context.get_value(&identifier).ok_or_else(|| { VmError::UndefinedVariable { identifier: Node::new( Statement::Identifier(identifier.clone()), @@ -116,7 +118,7 @@ impl Vm { position: left.position, }); }; - let right_value = if let Some(value) = self.run_statement(*right, context)? { + let right_value = if let Some(value) = self.run_statement(*right)? { value } else { return Err(VmError::ExpectedValue { @@ -130,20 +132,20 @@ impl Vm { } })?; - context.set_value(identifier, new_value); + self.context.set_value(identifier, new_value); return Ok(None); } let left_position = left.position; - let left_value = if let Some(value) = self.run_statement(*left, context)? { + let left_value = if let Some(value) = self.run_statement(*left)? { value } else { return Err(VmError::ExpectedValue { position: left_position, }); }; - let right_value = if let Some(value) = self.run_statement(*right, context)? { + let right_value = if let Some(value) = self.run_statement(*right)? { value } else { return Err(VmError::ExpectedValue { @@ -178,7 +180,7 @@ impl Vm { let mut previous_value = None; for statement in statements { - previous_value = self.run_statement(statement, context)?; + previous_value = self.run_statement(statement)?; } Ok(previous_value) @@ -193,7 +195,7 @@ impl Vm { for node in nodes { let position = node.position; - let value = if let Some(value) = self.run_statement(node, context)? { + let value = if let Some(value) = self.run_statement(node)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -223,14 +225,13 @@ 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)? { - value - } else { - return Err(VmError::ExpectedValue { - position: function_position, - }); - }; + let function_value = if let Some(value) = self.run_statement(*function_node)? { + value + } else { + return Err(VmError::ExpectedValue { + position: function_position, + }); + }; let function = if let Some(function) = function_value.as_function() { function } else { @@ -245,7 +246,7 @@ impl Vm { for node in value_nodes { let position = node.position; - let value = if let Some(value) = self.run_statement(node, context)? { + let value = if let Some(value) = self.run_statement(node)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -259,10 +260,12 @@ impl Vm { None }; - Ok(function.clone().call(None, value_parameters, context)?) + Ok(function + .clone() + .call(None, value_parameters, &self.context)?) } Statement::Identifier(identifier) => { - let value_option = context.get_value(&identifier); + let value_option = self.context.get_value(&identifier); if let Some(value) = value_option { Ok(Some(value.clone())) @@ -274,14 +277,13 @@ impl Vm { } Statement::If { condition, body } => { let condition_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_value = if let Some(value) = self.run_statement(*condition)? { + value + } else { + return Err(VmError::ExpectedValue { + position: condition_position, + }); + }; let condition = if let Some(condition) = condition_value.as_boolean() { condition } else { @@ -291,7 +293,7 @@ impl Vm { }; if condition { - self.run_statement(*body, context)?; + self.run_statement(*body)?; } Ok(None) @@ -302,20 +304,19 @@ impl Vm { else_body, } => { let condition_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_value = if let Some(value) = self.run_statement(*condition)? { + 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) + self.run_statement(*if_body) } else { - self.run_statement(*else_body, context) + self.run_statement(*else_body) } } else { Err(VmError::ExpectedBoolean { @@ -329,23 +330,22 @@ impl Vm { else_ifs, } => { let condition_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_value = if let Some(value) = self.run_statement(*condition)? { + 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) + self.run_statement(*if_body) } else { for (condition, body) in else_ifs { let condition_position = condition.position; let condition_value = - if let Some(value) = self.run_statement(condition, context)? { + if let Some(value) = self.run_statement(condition)? { value } else { return Err(VmError::ExpectedValue { @@ -361,7 +361,7 @@ impl Vm { }; if condition { - self.run_statement(body, context)?; + self.run_statement(body)?; } } @@ -380,23 +380,22 @@ impl Vm { else_body, } => { let condition_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_value = if let Some(value) = self.run_statement(*condition)? { + 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) + self.run_statement(*if_body) } else { for (condition, body) in else_ifs { let condition_position = condition.position; let condition_value = - if let Some(value) = self.run_statement(condition, context)? { + if let Some(value) = self.run_statement(condition)? { value } else { return Err(VmError::ExpectedValue { @@ -412,11 +411,11 @@ impl Vm { }; if condition { - return self.run_statement(body, context); + return self.run_statement(body); } } - self.run_statement(*else_body, context) + self.run_statement(*else_body) } } else { Err(VmError::ExpectedBoolean { @@ -429,7 +428,7 @@ impl Vm { .into_iter() .map(|node| { let span = node.position; - if let Some(value) = self.run_statement(node, context)? { + if let Some(value) = self.run_statement(node)? { Ok(value) } else { Err(VmError::ExpectedValue { position: span }) @@ -451,7 +450,7 @@ impl Vm { }); }; let position = value_node.position; - let value = if let Some(value) = self.run_statement(value_node, context)? { + let value = if let Some(value) = self.run_statement(value_node)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -463,13 +462,13 @@ impl Vm { Ok(Some(Value::map(values))) } Statement::Nil(node) => { - let _return = self.run_statement(*node, context)?; + let _return = self.run_statement(*node)?; Ok(None) } Statement::PropertyAccess(left, right) => { let left_span = left.position; - let left_value = if let Some(value) = self.run_statement(*left, context)? { + let left_value = if let Some(value) = self.run_statement(*left)? { value } else { return Err(VmError::ExpectedValue { @@ -502,7 +501,7 @@ impl Vm { } Statement::UnaryOperation { operator, operand } => { let position = operand.position; - let value = if let Some(value) = self.run_statement(*operand, context)? { + let value = if let Some(value) = self.run_statement(*operand)? { value } else { return Err(VmError::ExpectedValue { position }); @@ -532,7 +531,7 @@ impl Vm { let condition_position = condition.position; - while let Some(condition_value) = self.run_statement(*condition.clone(), context)? { + while let Some(condition_value) = self.run_statement(*condition.clone())? { if let ValueInner::Boolean(condition_value) = condition_value.inner().as_ref() { if !condition_value { break; @@ -543,7 +542,7 @@ impl Vm { }); } - return_value = self.run_statement(*body.clone(), context)?; + return_value = self.run_statement(*body.clone())?; if return_value.is_some() { break;