From b02e5244f25992a6973aa6202bda7c23b3c4e252 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 28 Aug 2024 11:31:47 -0400 Subject: [PATCH] Add defereference expressions --- dust-lang/src/analyzer.rs | 3 +++ dust-lang/src/ast/expression.rs | 8 ++++++ dust-lang/src/parser.rs | 25 ++++++++++++++++- dust-lang/src/token.rs | 2 +- dust-lang/src/value.rs | 17 +++++++++++- dust-lang/src/vm.rs | 48 ++++++++++++++++++++++----------- 6 files changed, 85 insertions(+), 18 deletions(-) diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 6bd04a9..52aca99 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -314,6 +314,9 @@ impl<'a> Analyzer<'a> { self.analyze_expression(argument, statement_position); } } + Expression::Dereference(expression) => { + self.analyze_expression(&expression.inner, statement_position); + } Expression::FieldAccess(field_access_expression) => { let FieldAccessExpression { container, field } = field_access_expression.inner.as_ref(); diff --git a/dust-lang/src/ast/expression.rs b/dust-lang/src/ast/expression.rs index a651488..932c79a 100644 --- a/dust-lang/src/ast/expression.rs +++ b/dust-lang/src/ast/expression.rs @@ -18,6 +18,7 @@ pub enum Expression { Block(Node>), Break(Node>>), Call(Node>), + Dereference(Node>), FieldAccess(Node>), Grouped(Node>), Identifier(Node), @@ -34,6 +35,10 @@ pub enum Expression { } impl Expression { + pub fn dereference(expression: Expression, position: Span) -> Self { + Self::Dereference(Node::new(Box::new(expression), position)) + } + pub fn r#break(expression: Option, position: Span) -> Self { Self::Break(Node::new(expression.map(Box::new), position)) } @@ -304,6 +309,7 @@ impl Expression { } } } + Expression::Dereference(expression) => expression.inner.type_evaluation(context)?, Expression::FieldAccess(field_access_expression) => { let FieldAccessExpression { container, field } = field_access_expression.inner.as_ref(); @@ -571,6 +577,7 @@ impl Expression { Expression::Block(block) => block.position, Expression::Break(expression_node) => expression_node.position, Expression::Call(call) => call.position, + Expression::Dereference(expression_node) => expression_node.position, Expression::FieldAccess(field_access) => field_access.position, Expression::Grouped(grouped) => grouped.position, Expression::Identifier(identifier) => identifier.position, @@ -600,6 +607,7 @@ impl Display for Expression { } } Expression::Call(call) => write!(f, "{}", call.inner), + Expression::Dereference(expression_node) => write!(f, "*{}", expression_node.inner), Expression::FieldAccess(field_access) => write!(f, "{}", field_access.inner), Expression::Grouped(grouped) => write!(f, "({})", grouped.inner), Expression::Identifier(identifier) => write!(f, "{}", identifier.inner), diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index a23f833..790de83 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -369,8 +369,16 @@ impl<'src> Parser<'src> { Ok(Expression::negation(operand, position)) } + Token::Star => { + self.next_token()?; + + let operand = self.parse_expression(0)?; + let position = (operator_start, self.current_position.1); + + Ok(Expression::dereference(operand, position)) + } _ => Err(ParseError::ExpectedTokenMultiple { - expected: vec![TokenKind::Bang, TokenKind::Minus], + expected: vec![TokenKind::Bang, TokenKind::Minus, TokenKind::Star], actual: self.current_token.to_owned(), position: self.current_position, }), @@ -1157,6 +1165,21 @@ mod tests { use super::*; + #[test] + fn dereference() { + let source = "*a"; + + assert_eq!( + parse(source), + Ok(AbstractSyntaxTree::with_statements([ + Statement::Expression(Expression::dereference( + Expression::identifier(Identifier::new("a"), (1, 2)), + (0, 2) + ),) + ])) + ); + } + #[test] fn character_literal() { let source = "'a'"; diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index 69a543c..2e41d95 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -270,7 +270,7 @@ impl<'src> Token<'src> { } pub fn is_prefix(&self) -> bool { - matches!(self, Token::Bang | Token::Minus) + matches!(self, Token::Bang | Token::Minus | Token::Star) } pub fn is_postfix(&self) -> bool { diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index c2d24e7..3963eb2 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -130,6 +130,14 @@ impl Value { } } + pub fn into_raw(self) -> Self { + match self { + Value::Raw(_) => self, + Value::Reference(data) => Value::Raw(data.as_ref().clone()), + Value::Mutable(data) => Value::Raw(data.read().unwrap().clone()), + } + } + pub fn into_reference(self) -> Self { match self { Value::Raw(data) => Value::Reference(Arc::new(data)), @@ -158,6 +166,13 @@ impl Value { } } + pub fn is_raw(&self) -> bool { + match self { + Value::Raw(_) => true, + _ => false, + } + } + pub fn as_mutable(&self) -> Option<&Arc>> { match self { Value::Mutable(data) => Some(data), @@ -1398,7 +1413,7 @@ impl Function { } } - let mut vm = Vm::new(new_context); + let vm = Vm::new(new_context); vm.run(body) .map_err(|error| FunctionCallError::Runtime(Box::new(error))) diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 74cd42f..1eae447 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -7,7 +7,6 @@ use std::{ collections::HashMap, fmt::{self, Display, Formatter}, - rc::Weak, sync::{Arc, Mutex}, }; @@ -243,18 +242,12 @@ impl Vm { let position = value.position(); let value = self .run_expression(value, collect_garbage)? - .expect_value(position)?; - - let reference = match value { - Value::Raw(_) => value.into_reference(), - Value::Reference(_) => value, - Value::Mutable(_) => { - return Err(RuntimeError::CannotAssignToMutable { position }); - } - }; + .expect_value(position)? + .into_raw() + .into_reference(); self.context - .set_variable_value(identifier.inner, reference) + .set_variable_value(identifier.inner, value) .map_err(|error| RuntimeError::ContextError { error, position })?; Ok(()) @@ -264,6 +257,7 @@ impl Vm { let mutable_value = self .run_expression(value, collect_garbage)? .expect_value(position)? + .into_raw() .into_mutable(); self.context @@ -309,6 +303,22 @@ impl Vm { Ok(evaluation) } Expression::Call(call) => self.run_call(*call.inner, collect_garbage), + Expression::Dereference(Node { inner, .. }) => { + let run_expression = self.run_expression(*inner, collect_garbage)?; + let evaluation = match run_expression { + Evaluation::Constructor(_) => { + return Err(RuntimeError::ExpectedValue { position }) + } + Evaluation::Return(value_option) => { + Evaluation::Return(value_option.map(|value| value.into_raw())) + } + Evaluation::Break(value_option) => { + Evaluation::Break(value_option.map(|value| value.into_raw())) + } + }; + + Ok(evaluation) + } Expression::FieldAccess(field_access) => { self.run_field_access(*field_access.inner, collect_garbage) } @@ -978,7 +988,8 @@ impl Vm { let position = repeat_operand.position(); let value = self .run_expression(repeat_operand, collect_garbage)? - .expect_value(position)?; + .expect_value(position)? + .into_raw(); Ok(Evaluation::Return(Some(Value::list(vec![ value; @@ -1417,13 +1428,20 @@ mod tests { use super::*; + #[test] + fn dereference_variable() { + let source = "let x = 42; let y = x; *y"; + + assert!(run(source).unwrap().unwrap().is_raw()); + } + #[test] fn mutate_copied_variable() { let source = "let mut x = 42; let y = [x; 3]; x += 1; y"; assert_eq!( run(source), - Ok(Some(Value::list([43.into(), 43.into(), 43.into()]))) + Ok(Some(Value::list([42.into(), 42.into(), 42.into()]))) ); } @@ -1443,9 +1461,9 @@ mod tests { #[test] fn mutate_assigned_variable() { - let source = "let mut x = 42; let mut y = x; x += 1; y"; + let source = "let mut x = 42; let y = x; x += 1; y"; - assert_eq!(run(source), Ok(Some(Value::integer(43)))); + assert_eq!(run(source), Ok(Some(Value::integer(42)))); } #[test]