From 84429ef187c9faff91fb5cb62fb83a0fb7bd5b23 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 16 Aug 2024 06:43:29 -0400 Subject: [PATCH] Implement operator expressions in the VM --- dust-lang/src/value.rs | 48 +++++++-- dust-lang/src/vm.rs | 222 +++++++++++++++++++++++++++++++++++------ 2 files changed, 230 insertions(+), 40 deletions(-) diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 2d29cbe..c8bd915 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -114,18 +114,18 @@ impl Value { } } - pub fn mutate(&self, other: &Value) { - let other_data = match other { - Value::Immutable(inner) => inner.as_ref().clone(), - Value::Mutable(inner_locked) => inner_locked.read().unwrap().clone(), + pub fn mutate(&self, other: Value) -> Result<(), ValueError> { + let mut inner = match self { + Value::Immutable(_) => return Err(ValueError::CannotMutate(self.clone())), + Value::Mutable(inner) => inner.write().unwrap(), }; - match self { - Value::Mutable(locked) => { - *locked.write().unwrap() = other_data; - } - Value::Immutable(_) => todo!(), + match other { + Value::Immutable(other) => *inner = other.as_ref().clone(), + Value::Mutable(other) => *inner = other.read().unwrap().clone(), } + + Ok(()) } pub fn r#type(&self) -> Type { @@ -627,6 +627,36 @@ impl Value { Err(ValueError::CannotModulo(self.clone(), other.clone())) } + pub fn equal(&self, other: &Value) -> Value { + let is_equal = match (self, other) { + (Value::Immutable(left), Value::Immutable(right)) => left == right, + (Value::Mutable(left), Value::Mutable(right)) => { + *left.read().unwrap() == *right.read().unwrap() + } + (Value::Immutable(arc), Value::Mutable(arc_locked)) + | (Value::Mutable(arc_locked), Value::Immutable(arc)) => { + *arc_locked.read().unwrap() == *arc.as_ref() + } + }; + + Value::boolean(is_equal) + } + + pub fn not_equal(&self, other: &Value) -> Value { + let is_not_equal = match (self, other) { + (Value::Immutable(left), Value::Immutable(right)) => left != right, + (Value::Mutable(left), Value::Mutable(right)) => { + *left.read().unwrap() != *right.read().unwrap() + } + (Value::Immutable(arc), Value::Mutable(arc_locked)) + | (Value::Mutable(arc_locked), Value::Immutable(arc)) => { + *arc_locked.read().unwrap() != *arc.as_ref() + } + }; + + Value::boolean(is_not_equal) + } + pub fn less_than(&self, other: &Value) -> Result { match (self, other) { (Value::Immutable(left), Value::Immutable(right)) => { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 9807508..d192c3b 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -13,9 +13,10 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterato use crate::{ ast::{ - AbstractSyntaxTree, BlockExpression, CallExpression, ElseExpression, FieldAccessExpression, - IfExpression, ListExpression, ListIndexExpression, LiteralExpression, LoopExpression, Node, - OperatorExpression, Statement, + AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression, + FieldAccessExpression, IfExpression, ListExpression, ListIndexExpression, + LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression, + Statement, }, parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError, Span, Type, Value, ValueError, @@ -135,13 +136,26 @@ impl Vm { Expression::Call(call) => self.run_call(*call.inner), Expression::FieldAccess(field_access) => self.run_field_access(*field_access.inner), Expression::Grouped(expression) => self.run_expression(*expression.inner), - Expression::Identifier(identifier) => self.run_identifier(identifier.inner), + Expression::Identifier(identifier) => { + let get_value = self.context.get_value(&identifier.inner); + + if let Some(value) = get_value { + Ok(Evaluation::Return(Some(value))) + } else { + Err(VmError::UndefinedVariable { + identifier: identifier.inner, + position: identifier.position, + }) + } + } Expression::If(if_expression) => self.run_if(*if_expression.inner), Expression::List(list_expression) => self.run_list(*list_expression.inner), Expression::ListIndex(list_index) => self.run_list_index(*list_index.inner), Expression::Literal(literal) => self.run_literal(*literal.inner), Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner), - Expression::Operator(_) => todo!(), + Expression::Operator(operator_expression) => { + self.run_operator(*operator_expression.inner) + } Expression::Range(_) => todo!(), Expression::Struct(_) => todo!(), Expression::TupleAccess(_) => todo!(), @@ -155,12 +169,63 @@ impl Vm { fn run_operator(&self, operator: OperatorExpression) -> Result { match operator { - OperatorExpression::Assignment { assignee, value } => todo!(), + OperatorExpression::Assignment { assignee, value } => { + let assignee_position = assignee.position(); + let assignee = self + .run_expression(assignee)? + .expect_value(assignee_position)?; + let value_position = value.position(); + let value = self.run_expression(value)?.expect_value(value_position)?; + + assignee.mutate(value); + + Ok(Evaluation::Return(None)) + } OperatorExpression::Comparison { left, operator, right, - } => todo!(), + } => { + let left_position = left.position(); + let left_value = self.run_expression(left)?.expect_value(left_position)?; + let right_position = right.position(); + let right_value = self.run_expression(right)?.expect_value(right_position)?; + let outcome = + match operator.inner { + ComparisonOperator::Equal => left_value.equal(&right_value), + ComparisonOperator::NotEqual => left_value.not_equal(&right_value), + ComparisonOperator::GreaterThan => left_value + .greater_than(&right_value) + .map_err(|error| VmError::ValueError { + error, + left_position, + right_position, + })?, + ComparisonOperator::GreaterThanOrEqual => left_value + .greater_than_or_equal(&right_value) + .map_err(|error| VmError::ValueError { + error, + left_position, + right_position, + })?, + ComparisonOperator::LessThan => left_value + .less_than(&right_value) + .map_err(|error| VmError::ValueError { + error, + left_position, + right_position, + })?, + ComparisonOperator::LessThanOrEqual => left_value + .less_than_or_equal(&right_value) + .map_err(|error| VmError::ValueError { + error, + left_position, + right_position, + })?, + }; + + Ok(Evaluation::Return(Some(outcome))) + } OperatorExpression::CompoundAssignment { assignee, operator, @@ -173,12 +238,47 @@ impl Vm { left, operator, right, - } => todo!(), + } => { + let left_position = left.position(); + let left_value = self.run_expression(left)?.expect_value(left_position)?; + let right_position = right.position(); + let right_value = self.run_expression(right)?.expect_value(right_position)?; + let outcome = match operator.inner { + MathOperator::Add => left_value.add(&right_value), + MathOperator::Subtract => left_value.subtract(&right_value), + MathOperator::Multiply => left_value.multiply(&right_value), + MathOperator::Divide => left_value.divide(&right_value), + MathOperator::Modulo => left_value.modulo(&right_value), + } + .map_err(|value_error| VmError::ValueError { + error: value_error, + left_position, + right_position, + })?; + + Ok(Evaluation::Return(Some(outcome))) + } OperatorExpression::Logic { left, operator, right, - } => todo!(), + } => { + let left_position = left.position(); + let left_value = self.run_expression(left)?.expect_value(left_position)?; + let right_position = right.position(); + let right_value = self.run_expression(right)?.expect_value(right_position)?; + let outcome = match operator.inner { + LogicOperator::And => left_value.and(&right_value), + LogicOperator::Or => left_value.or(&right_value), + } + .map_err(|value_error| VmError::ValueError { + error: value_error, + left_position, + right_position, + })?; + + Ok(Evaluation::Return(Some(outcome))) + } } } @@ -267,7 +367,7 @@ impl Vm { function .call(None, Some(value_arguments), &context) - .map(|value_option| Evaluation::Return(value_option)) + .map(Evaluation::Return) } fn run_field_access(&self, field_access: FieldAccessExpression) -> Result { @@ -285,16 +385,6 @@ impl Vm { Ok(Evaluation::Return(container_value.get_field(&field.inner))) } - fn run_identifier(&self, identifier: Identifier) -> Result { - let value_option = self.context.get_value(&identifier); - - if let Some(value) = value_option { - Ok(Evaluation::Return(Some(value))) - } else { - Err(VmError::UndefinedVariable { identifier }) - } - } - fn run_list(&self, list_expression: ListExpression) -> Result { match list_expression { ListExpression::AutoFill { @@ -336,19 +426,33 @@ impl Vm { fn run_block(&self, block: BlockExpression) -> Result { match block { BlockExpression::Async(statements) => { - let expected_return = statements.last().unwrap().expected_type(); - let final_result = Arc::new(Mutex::new(None)); + let statements_length = statements.len(); + let error_option = + statements + .into_par_iter() + .enumerate() + .find_map_any(|(i, statement)| { + let evaluation_result = self.run_statement(statement); - let error_option = statements - .into_par_iter() - .enumerate() - .find_map_any(|statement| self.run_statement(statement).err()); + match evaluation_result { + Ok(evaluation) => { + if i == statements_length - 1 { + let mut final_result = final_result.lock().unwrap(); + + *final_result = evaluation; + } + + None + } + Err(error) => Some(error), + } + }); if let Some(error) = error_option { Err(error) } else { - Ok(Evaluation::Return(None)) + Ok(Evaluation::Return(final_result.lock().unwrap().clone())) } } BlockExpression::Sync(statements) => { @@ -446,7 +550,8 @@ pub enum VmError { }, ValueError { error: ValueError, - position: Span, + left_position: Span, + right_position: Span, }, // Anaylsis Failures @@ -492,6 +597,7 @@ pub enum VmError { }, UndefinedVariable { identifier: Identifier, + position: Span, }, UndefinedProperty { value: Value, @@ -501,6 +607,36 @@ pub enum VmError { }, } +impl VmError { + pub fn position(&self) -> Span { + match self { + Self::ParseError(parse_error) => parse_error.position(), + Self::Trace { position, .. } => *position, + Self::ValueError { + left_position, + right_position, + .. + } => (left_position.0, right_position.1), + Self::BuiltInFunctionError { position, .. } => *position, + Self::CannotMutate { position, .. } => *position, + Self::ExpectedBoolean { position } => *position, + Self::ExpectedIdentifier { position } => *position, + Self::ExpectedIntegerOrRange { position } => *position, + Self::ExpectedIdentifierOrString { position } => *position, + Self::ExpectedInteger { position } => *position, + Self::ExpectedNumber { position } => *position, + Self::ExpectedMap { position } => *position, + Self::ExpectedFunction { position, .. } => *position, + Self::ExpectedList { position } => *position, + Self::ExpectedValue { position } => *position, + Self::UndefinedVariable { position, .. } => *position, + Self::UndefinedProperty { + property_position, .. + } => *property_position, + } + } +} + impl From for VmError { fn from(error: ParseError) -> Self { Self::ParseError(error) @@ -518,7 +654,17 @@ impl Display for VmError { position, error ) } - Self::ValueError { error, .. } => write!(f, "{}", error), + Self::ValueError { + error, + left_position, + right_position, + } => { + write!( + f, + "Value error with values at positions: {:?} and {:?} {}", + left_position, right_position, error + ) + } Self::CannotMutate { value, .. } => { write!(f, "Cannot mutate immutable value {}", value) } @@ -571,8 +717,15 @@ impl Display for VmError { Self::ExpectedValue { position } => { write!(f, "Expected a value at position: {:?}", position) } - Self::UndefinedVariable { identifier } => { - write!(f, "Undefined identifier: {}", identifier) + Self::UndefinedVariable { + identifier, + position, + } => { + write!( + f, + "Undefined variable {} at position: {:?}", + identifier, position + ) } Self::UndefinedProperty { value, property, .. @@ -816,6 +969,13 @@ mod tests { assert_eq!(run(input), Ok(Some(Value::integer(2)))); } + #[test] + fn and() { + let input = "true && true"; + + assert_eq!(run(input), Ok(Some(Value::boolean(true)))); + } + #[test] fn or() { let input = "true || false";