diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 3fbf62d..99eb0d6 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -10,8 +10,8 @@ use std::{ }; use crate::{ - ast::{AbstractSyntaxTree, Node, Statement}, - parse, Context, DustError, Identifier, Span, Type, + ast::{AbstractSyntaxTree, LetStatement, Node, OperatorExpression, Statement}, + parse, Context, DustError, Expression, Identifier, Span, Type, }; /// Analyzes the abstract syntax tree for errors. @@ -65,14 +65,125 @@ impl<'a> Analyzer<'a> { } pub fn analyze(&mut self) -> Result<(), AnalyzerError> { - for node in &self.abstract_tree.statements { - self.analyze_statement(node)?; + for statement in &self.abstract_tree.statements { + self.analyze_statement(statement)?; } Ok(()) } - fn analyze_statement(&mut self, _: &Statement) -> Result<(), AnalyzerError> { + fn analyze_statement(&mut self, statement: &Statement) -> Result<(), AnalyzerError> { + match statement { + Statement::Expression(expression) => self.analyze_expression(expression)?, + Statement::ExpressionNullified(expression_node) => { + self.analyze_expression(&expression_node.inner)?; + } + Statement::Let(let_statement) => match &let_statement.inner { + LetStatement::Let { identifier, value } => { + let type_option = value.return_type(self.context); + + if let Some(r#type) = type_option { + self.context.set_type( + identifier.inner.clone(), + r#type, + identifier.position, + ); + } else { + return Err(AnalyzerError::UndefinedVariable { + identifier: identifier.clone(), + }); + } + + self.analyze_expression(value)?; + } + LetStatement::LetMut { identifier, value } => { + let type_option = value.return_type(self.context); + + if let Some(r#type) = type_option { + self.context.set_type( + identifier.inner.clone(), + r#type, + identifier.position, + ); + } else { + return Err(AnalyzerError::UndefinedVariable { + identifier: identifier.clone(), + }); + } + + self.analyze_expression(value)?; + } + LetStatement::LetType { + identifier, + r#type, + value, + } => todo!(), + LetStatement::LetMutType { + identifier, + r#type, + value, + } => todo!(), + }, + Statement::StructDefinition(_) => {} + } + + Ok(()) + } + + fn analyze_expression(&mut self, expression: &Expression) -> Result<(), AnalyzerError> { + match expression { + Expression::Block(_) => {} + Expression::Call(_) => {} + Expression::FieldAccess(_) => {} + Expression::Grouped(_) => {} + Expression::Identifier(identifier) => { + let found = self + .context + .update_last_position(&identifier.inner, identifier.position); + + if !found { + return Err(AnalyzerError::UndefinedVariable { + identifier: identifier.clone(), + }); + } + } + Expression::If(_) => {} + Expression::List(_) => {} + Expression::ListIndex(_) => {} + Expression::Literal(_) => {} + Expression::Loop(_) => {} + Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() { + OperatorExpression::Assignment { assignee, value } => { + self.analyze_expression(assignee)?; + self.analyze_expression(value)?; + } + OperatorExpression::Comparison { left, right, .. } => { + self.analyze_expression(left)?; + self.analyze_expression(right)?; + } + OperatorExpression::CompoundAssignment { + assignee, modifier, .. + } => { + self.analyze_expression(assignee)?; + self.analyze_expression(modifier)?; + } + OperatorExpression::ErrorPropagation(_) => todo!(), + OperatorExpression::Negation(_) => todo!(), + OperatorExpression::Not(_) => todo!(), + OperatorExpression::Math { left, right, .. } => { + self.analyze_expression(left)?; + self.analyze_expression(right)?; + } + OperatorExpression::Logic { left, right, .. } => { + self.analyze_expression(left)?; + self.analyze_expression(right)?; + } + }, + Expression::Range(_) => {} + Expression::Struct(_) => {} + Expression::TupleAccess(_) => {} + } + Ok(()) } } @@ -124,13 +235,13 @@ pub enum AnalyzerError { identifier: Node, }, UnexpectedIdentifier { - identifier: Statement, + identifier: Node, }, UnexectedString { actual: Statement, }, UndefinedVariable { - identifier: Statement, + identifier: Node, }, } @@ -151,8 +262,8 @@ impl AnalyzerError { } => actual_statement.position(), AnalyzerError::UndefinedField { identifier, .. } => identifier.position(), AnalyzerError::UndefinedType { identifier } => identifier.position, - AnalyzerError::UndefinedVariable { identifier } => identifier.position(), - AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position(), + AnalyzerError::UndefinedVariable { identifier } => identifier.position, + AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position, AnalyzerError::UnexectedString { actual } => actual.position(), } } diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 6329e6a..21b2b45 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -170,6 +170,10 @@ impl<'src> Parser<'src> { let value = self.parse_expression(0)?; + if let Token::Semicolon = self.current_token { + self.next_token()?; + } + let r#let = if is_mutable { LetStatement::LetMut { identifier, value } } else { diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index dd32287..7624d27 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -366,7 +366,7 @@ impl Display for TokenOwned { TokenOwned::Async => Token::Async.fmt(f), TokenOwned::Bang => Token::Bang.fmt(f), TokenOwned::BangEqual => Token::BangEqual.fmt(f), - TokenOwned::Bool => write!(f, "bool"), + TokenOwned::Bool => Token::Bool.fmt(f), TokenOwned::Boolean(boolean) => write!(f, "{boolean}"), TokenOwned::Colon => Token::Colon.fmt(f), TokenOwned::Comma => Token::Comma.fmt(f), @@ -379,12 +379,12 @@ impl Display for TokenOwned { TokenOwned::Eof => Token::Eof.fmt(f), TokenOwned::Equal => Token::Equal.fmt(f), TokenOwned::Float(float) => write!(f, "{float}"), - TokenOwned::FloatKeyword => write!(f, "float"), + TokenOwned::FloatKeyword => Token::FloatKeyword.fmt(f), TokenOwned::Greater => Token::Greater.fmt(f), TokenOwned::GreaterOrEqual => Token::GreaterEqual.fmt(f), TokenOwned::Identifier(text) => write!(f, "{text}"), TokenOwned::If => Token::If.fmt(f), - TokenOwned::Int => write!(f, "int"), + TokenOwned::Int => Token::Int.fmt(f), TokenOwned::Integer(integer) => write!(f, "{integer}"), TokenOwned::IsEven => Token::IsEven.fmt(f), TokenOwned::IsOdd => Token::IsOdd.fmt(f), @@ -408,7 +408,7 @@ impl Display for TokenOwned { TokenOwned::Semicolon => Token::Semicolon.fmt(f), TokenOwned::Star => Token::Star.fmt(f), TokenOwned::Slash => Token::Slash.fmt(f), - TokenOwned::Str => write!(f, "str"), + TokenOwned::Str => Token::Str.fmt(f), TokenOwned::String(string) => write!(f, "{string}"), TokenOwned::Struct => Token::Struct.fmt(f), TokenOwned::ToString => Token::ToString.fmt(f), diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index c8bd915..0dd48fe 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -105,12 +105,17 @@ impl Value { matches!(self, Value::Mutable(_)) } - pub fn to_mut(self) -> Self { - match self { - Value::Immutable(inner) => { - Value::Mutable(Arc::new(RwLock::new(inner.as_ref().clone()))) - } - _ => self, + pub fn to_mut(self) -> Result { + if let Value::Immutable(arc) = self { + let value_data = if let Some(value_data) = Arc::into_inner(arc) { + value_data + } else { + return Err(ValueError::CannotMakeMutable); + }; + + Ok(Value::Mutable(Arc::new(RwLock::new(value_data)))) + } else { + Ok(self) } } @@ -317,7 +322,7 @@ impl Value { Err(ValueError::CannotAdd(self.clone(), other.clone())) } - pub fn add_mut(&self, other: &Value) -> Result<(), ValueError> { + pub fn add_assign(&self, other: &Value) -> Result<(), ValueError> { match (self, other) { (Value::Mutable(left), Value::Mutable(right)) => { match (&mut *left.write().unwrap(), &*right.read().unwrap()) { @@ -412,7 +417,7 @@ impl Value { Err(ValueError::CannotSubtract(self.clone(), other.clone())) } - pub fn subtract_mut(&self, other: &Value) -> Result<(), ValueError> { + pub fn subtract_assign(&self, other: &Value) -> Result<(), ValueError> { match (self, other) { (Value::Mutable(left), Value::Mutable(right)) => { match (&mut *left.write().unwrap(), &*right.read().unwrap()) { @@ -489,6 +494,42 @@ impl Value { Err(ValueError::CannotMultiply(self.clone(), other.clone())) } + pub fn multiply_assign(&self, other: &Value) -> Result<(), ValueError> { + match (self, other) { + (Value::Mutable(left), Value::Mutable(right)) => { + match (&mut *left.write().unwrap(), &*right.read().unwrap()) { + (ValueData::Float(left), ValueData::Float(right)) => { + *left *= right; + return Ok(()); + } + (ValueData::Integer(left), ValueData::Integer(right)) => { + *left = left.saturating_mul(*right); + return Ok(()); + } + _ => {} + } + } + (Value::Mutable(left), Value::Immutable(right)) => { + match (&mut *left.write().unwrap(), right.as_ref()) { + (ValueData::Float(left), ValueData::Float(right)) => { + *left *= right; + return Ok(()); + } + (ValueData::Integer(left), ValueData::Integer(right)) => { + *left = left.saturating_mul(*right); + return Ok(()); + } + _ => {} + } + } + (Value::Immutable(_), _) => { + return Err(ValueError::CannotMutate(self.clone())); + } + } + + Err(ValueError::CannotMultiply(self.clone(), other.clone())) + } + pub fn divide(&self, other: &Value) -> Result { match (self, other) { (Value::Immutable(left), Value::Immutable(right)) => { @@ -564,6 +605,54 @@ impl Value { Err(ValueError::CannotDivide(self.clone(), other.clone())) } + pub fn divide_assign(&self, other: &Value) -> Result<(), ValueError> { + match (self, other) { + (Value::Mutable(left), Value::Mutable(right)) => { + match (&mut *left.write().unwrap(), &*right.read().unwrap()) { + (ValueData::Float(left), ValueData::Float(right)) => { + if *right == 0.0 { + return Err(ValueError::DivisionByZero); + } + *left /= right; + return Ok(()); + } + (ValueData::Integer(left), ValueData::Integer(right)) => { + if *right == 0 { + return Err(ValueError::DivisionByZero); + } + *left = left.saturating_div(*right); + return Ok(()); + } + _ => {} + } + } + (Value::Mutable(left), Value::Immutable(right)) => { + match (&mut *left.write().unwrap(), right.as_ref()) { + (ValueData::Float(left), ValueData::Float(right)) => { + if *right == 0.0 { + return Err(ValueError::DivisionByZero); + } + *left /= right; + return Ok(()); + } + (ValueData::Integer(left), ValueData::Integer(right)) => { + if *right == 0 { + return Err(ValueError::DivisionByZero); + } + *left = left.saturating_div(*right); + return Ok(()); + } + _ => {} + } + } + (Value::Immutable(_), _) => { + return Err(ValueError::CannotMutate(self.clone())); + } + } + + Err(ValueError::CannotDivide(self.clone(), other.clone())) + } + pub fn modulo(&self, other: &Value) -> Result { match (self, other) { (Value::Immutable(left), Value::Immutable(right)) => { @@ -627,6 +716,48 @@ impl Value { Err(ValueError::CannotModulo(self.clone(), other.clone())) } + pub fn modulo_assign(&self, other: &Value) -> Result<(), ValueError> { + match (self, other) { + (Value::Mutable(left), Value::Mutable(right)) => { + match (&mut *left.write().unwrap(), &*right.read().unwrap()) { + (ValueData::Float(left), ValueData::Float(right)) => { + *left %= right; + return Ok(()); + } + (ValueData::Integer(left), ValueData::Integer(right)) => { + if *right == 0 { + return Err(ValueError::DivisionByZero); + } + *left %= right; + return Ok(()); + } + _ => {} + } + } + (Value::Mutable(left), Value::Immutable(right)) => { + match (&mut *left.write().unwrap(), right.as_ref()) { + (ValueData::Float(left), ValueData::Float(right)) => { + *left %= right; + return Ok(()); + } + (ValueData::Integer(left), ValueData::Integer(right)) => { + if *right == 0 { + return Err(ValueError::DivisionByZero); + } + *left %= right; + return Ok(()); + } + _ => {} + } + } + (Value::Immutable(_), _) => { + return Err(ValueError::CannotMutate(self.clone())); + } + } + + 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, @@ -1614,6 +1745,7 @@ pub enum ValueError { CannotGreaterThanOrEqual(Value, Value), CannotLessThan(Value, Value), CannotLessThanOrEqual(Value, Value), + CannotMakeMutable, CannotModulo(Value, Value), CannotMultiply(Value, Value), CannotMutate(Value), @@ -1644,6 +1776,10 @@ impl Display for ValueError { ValueError::CannotMultiply(left, right) => { write!(f, "Cannot multiply {} and {}", left, right) } + ValueError::CannotMakeMutable => write!( + f, + "Failed to make mutable value because the value has an immutable reference to it" + ), ValueError::CannotMutate(value) => write!(f, "Cannot mutate {}", value), ValueError::CannotSubtract(left, right) => { write!(f, "Cannot subtract {} and {}", left, right) diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index d192c3b..ed25474 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -14,12 +14,12 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterato use crate::{ ast::{ AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression, - FieldAccessExpression, IfExpression, ListExpression, ListIndexExpression, + FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression, LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression, Statement, }, parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError, - Span, Type, Value, ValueError, + Span, Value, ValueError, }; /// Run the source code and return the result. @@ -90,21 +90,12 @@ impl Vm { } 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.statements.pop_front() { - let new_position = statement.position(); - previous_value = self.run_statement(statement)?; - - self.context.collect_garbage(previous_position.1); - - previous_position = new_position; } - self.context.collect_garbage(previous_position.1); - Ok(previous_value) } @@ -119,16 +110,50 @@ impl Vm { Ok(None) } - Statement::Let(_) => todo!(), + Statement::Let(let_statement) => { + self.run_let_statement(let_statement.inner)?; + + Ok(None) + } Statement::StructDefinition(_) => todo!(), }; + self.context.collect_garbage(position.1); + result.map_err(|error| VmError::Trace { error: Box::new(error), position, }) } + fn run_let_statement(&self, let_statement: LetStatement) -> Result<(), VmError> { + match let_statement { + LetStatement::Let { identifier, value } => { + let value_position = value.position(); + let value = self.run_expression(value)?.expect_value(value_position)?; + + self.context.set_value(identifier.inner, value); + + Ok(()) + } + LetStatement::LetMut { identifier, value } => { + let value_position = value.position(); + let value = self.run_expression(value)?.expect_value(value_position)?; + let mutable_value = value.to_mut().map_err(|error| VmError::ValueError { + error, + left_position: identifier.position, + right_position: value_position, + })?; + + self.context.set_value(identifier.inner, mutable_value); + + Ok(()) + } + LetStatement::LetType { .. } => todo!(), + LetStatement::LetMutType { .. } => todo!(), + } + } + fn run_expression(&self, expression: Expression) -> Result { let position = expression.position(); let evaluation_result = match expression { @@ -177,7 +202,13 @@ impl Vm { let value_position = value.position(); let value = self.run_expression(value)?.expect_value(value_position)?; - assignee.mutate(value); + assignee + .mutate(value) + .map_err(|error| VmError::ValueError { + error, + left_position: assignee_position, + right_position: value_position, + })?; Ok(Evaluation::Return(None)) } @@ -230,7 +261,31 @@ impl Vm { assignee, operator, modifier, - } => todo!(), + } => { + let assignee_position = assignee.position(); + let assignee = self + .run_expression(assignee)? + .expect_value(assignee_position)?; + let modifier_position = modifier.position(); + let modifier = self + .run_expression(modifier)? + .expect_value(modifier_position)?; + + match operator.inner { + MathOperator::Add => assignee.add_assign(&modifier), + MathOperator::Subtract => assignee.subtract_assign(&modifier), + MathOperator::Multiply => assignee.multiply_assign(&modifier), + MathOperator::Divide => assignee.divide_assign(&modifier), + MathOperator::Modulo => assignee.modulo_assign(&modifier), + } + .map_err(|error| VmError::ValueError { + error, + left_position: assignee_position, + right_position: modifier_position, + })?; + + Ok(Evaluation::Return(None)) + } OperatorExpression::ErrorPropagation(_) => todo!(), OperatorExpression::Negation(_) => todo!(), OperatorExpression::Not(_) => todo!(), @@ -742,30 +797,16 @@ mod tests { use super::*; - #[test] - fn mutate_variable() { - let input = " - mut x = '' - - x += 'foo' - x += 'bar' - - x - "; - - assert_eq!(run(input), Ok(Some(Value::string_mut("foobar")))); - } - #[test] fn async_block() { - let input = "mut x = 1; async { x += 1; x -= 1; } x"; + let input = "let mut x = 1; async { x += 1; x -= 1; } x"; assert!(run(input).unwrap().unwrap().as_integer().is_some()); } #[test] fn define_and_instantiate_fields_struct() { - let input = "struct Foo { bar: int, baz: float } Foo { bar = 42, baz = 4.0 }"; + let input = "struct Foo { bar: int, baz: float } Foo { bar: 42, baz: 4.0 }"; assert_eq!( run(input), @@ -844,20 +885,6 @@ mod tests { assert_eq!(run(input), Ok(Some(Value::integer(42)))); } - #[test] - fn map_property() { - let input = "{ x = 42 }.x"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - - #[test] - fn map_property_nested() { - let input = "{ x = { y = 42 } }.x.y"; - - assert_eq!(run(input), Ok(Some(Value::integer(42)))); - } - #[test] fn list_index_range() { let input = "[1, 2, 3, 4, 5][1..3]"; @@ -950,21 +977,23 @@ mod tests { #[test] fn while_loop() { - let input = "mut x = 0; while x < 5 { x += 1; } x"; + let input = "let mut x = 0; while x < 5 { x += 1; } x"; assert_eq!(run(input), Ok(Some(Value::integer(5)))); } #[test] fn subtract_assign() { - let input = "mut x = 1; x -= 1; x"; + let input = "let mut x = 1; x -= 1; x"; assert_eq!(run(input), Ok(Some(Value::integer(0)))); } #[test] fn add_assign() { - let input = "mut x = 1; x += 1; x"; + env_logger::builder().is_test(true).try_init().ok(); + + let input = "let mut x = 1; x += 1; x"; assert_eq!(run(input), Ok(Some(Value::integer(2)))); } @@ -983,13 +1012,6 @@ mod tests { assert_eq!(run(input), Ok(Some(Value::boolean(true)))); } - #[test] - fn map_equal() { - let input = "{ y = 'foo' } == { y = 'foo' }"; - - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); - } - #[test] fn integer_equal() { let input = "42 == 42";