From 8666f1cd9b3c0a88689f92710d32473f9f7735ed Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 14 Aug 2024 03:53:15 -0400 Subject: [PATCH] Add parsing for mutable assignment --- dust-lang/src/abstract_tree.rs | 8 +++ dust-lang/src/analyzer.rs | 18 +++-- dust-lang/src/parser.rs | 119 +++++++++++++++++++++++---------- dust-lang/src/value.rs | 25 +++++++ dust-lang/src/vm.rs | 14 +++- 5 files changed, 144 insertions(+), 40 deletions(-) diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index 325f55b..4fb063a 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -54,6 +54,10 @@ pub enum Statement { operator: Node, value: Box>, }, + MutAssignment { + identifier: Node, + value: Box>, + }, // Statement blocks, delimited by curly braces AsyncBlock(Vec>), @@ -214,6 +218,7 @@ impl Statement { Some(Type::Map(types)) } + Statement::MutAssignment { .. } => None, Statement::Nil(_) => None, Statement::UnaryOperation { operator, operand } => match operator.inner { UnaryOperator::Negate => Some(operand.inner.expected_type(context)?), @@ -447,6 +452,9 @@ impl Display for Statement { write!(f, "}}") } + Statement::MutAssignment { identifier, value } => { + write!(f, "mut {identifier} = {value}") + } Statement::Nil(node) => write!(f, "{node};"), Statement::UnaryOperation { operator, operand } => { let operator = match operator.inner { diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 5bc1a02..54bbb15 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -90,15 +90,11 @@ impl<'a> Analyzer<'a> { actual: value.as_ref().clone(), }); } - - return Ok(()); } Statement::AsyncBlock(statements) => { for statement in statements { self.analyze_statement(statement)?; } - - return Ok(()); } Statement::BinaryOperation { left, @@ -483,6 +479,20 @@ impl<'a> Analyzer<'a> { self.analyze_statement(value_node)?; } } + Statement::MutAssignment { identifier, value } => { + self.analyze_statement(value)?; + + let value_type = value.inner.expected_type(self.context); + + if let Some(r#type) = value_type { + self.context + .set_type(identifier.inner.clone(), r#type, identifier.position); + } else { + return Err(AnalyzerError::ExpectedValue { + actual: value.as_ref().clone(), + }); + } + } Statement::Nil(node) => { self.analyze_statement(node)?; } diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 617617f..9a39451 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -125,7 +125,7 @@ pub struct Parser<'src> { source: &'src str, lexer: Lexer, current: (Token<'src>, Span), - context: ParserContext, + mode: ParserMode, } impl<'src> Parser<'src> { @@ -137,7 +137,7 @@ impl<'src> Parser<'src> { source, lexer, current, - context: ParserContext::None, + mode: ParserMode::None, } } @@ -158,12 +158,8 @@ impl<'src> Parser<'src> { fn parse_statement(&mut self, mut precedence: u8) -> Result, ParseError> { // Parse a statement starting from the current node. let mut left = if self.current.0.is_prefix() { - log::trace!("Parsing {} as prefix operator", self.current.0); - self.parse_prefix()? } else { - log::trace!("Parsing {} as primary", self.current.0); - self.parse_primary()? }; @@ -171,26 +167,45 @@ impl<'src> Parser<'src> { while precedence < self.current.0.precedence() { // Give precedence to postfix operations left = if self.current.0.is_postfix() { - log::trace!("Parsing {} as postfix operator", self.current.0); - - // Replace the left-hand side with the postfix operation let statement = self.parse_postfix(left)?; precedence = self.current.0.precedence(); + // Replace the left-hand side with the postfix operation statement } else { - log::trace!("Parsing {} as infix operator", self.current.0); - // Replace the left-hand side with the infix operation self.parse_infix(left)? }; } + log::trace!( + "{}'s precedence is lower than or equal to {}", + self.current.0, + precedence + ); + Ok(left) } + fn parse_statement_in_mode( + &mut self, + mode: ParserMode, + precedence: u8, + ) -> Result, ParseError> { + let old_mode = self.mode; + self.mode = mode; + + let result = self.parse_statement(precedence); + + self.mode = old_mode; + + result + } + fn parse_prefix(&mut self) -> Result, ParseError> { + log::trace!("Parsing {} as prefix operator", self.current.0); + match self.current { (Token::Bang, position) => { self.next_token()?; @@ -228,6 +243,8 @@ impl<'src> Parser<'src> { } fn parse_primary(&mut self) -> Result, ParseError> { + log::trace!("Parsing {} as primary", self.current.0); + match self.current { (Token::Async, position) => { self.next_token()?; @@ -287,7 +304,7 @@ impl<'src> Parser<'src> { (Token::Identifier(text), position) => { self.next_token()?; - if let ParserContext::IfElseStatement = self.context { + if let ParserMode::Condition = self.mode { return Ok(Node::new( Statement::Identifier(Identifier::new(text)), position, @@ -379,9 +396,7 @@ impl<'src> Parser<'src> { (Token::If, position) => { self.next_token()?; - self.context = ParserContext::IfElseStatement; - - let condition = Box::new(self.parse_statement(0)?); + let condition = Box::new(self.parse_statement_in_mode(ParserMode::Condition, 0)?); let if_body = Box::new(self.parse_block()?); if let Token::Else = self.current.0 { @@ -390,7 +405,10 @@ impl<'src> Parser<'src> { if let Token::If = self.current.0 { self.next_token()?; - let first_else_if = (self.parse_statement(0)?, self.parse_statement(0)?); + let first_else_if = ( + self.parse_statement_in_mode(ParserMode::Condition, 0)?, + self.parse_statement(0)?, + ); let mut else_ifs = vec![first_else_if]; loop { @@ -410,15 +428,16 @@ impl<'src> Parser<'src> { if let Token::If = self.current.0 { self.next_token()?; - let else_if = (self.parse_statement(0)?, self.parse_statement(0)?); + let else_if = ( + self.parse_statement_in_mode(ParserMode::Condition, 0)?, + self.parse_statement(0)?, + ); else_ifs.push(else_if); } else { let else_body = Box::new(self.parse_block()?); let else_end = else_body.position.1; - self.context = ParserContext::None; - return Ok(Node::new( Statement::IfElseIfElse { condition, @@ -434,8 +453,6 @@ impl<'src> Parser<'src> { let else_body = Box::new(self.parse_block()?); let else_end = else_body.position.1; - self.context = ParserContext::None; - Ok(Node::new( Statement::IfElse { condition, @@ -448,7 +465,7 @@ impl<'src> Parser<'src> { } else { let if_end = if_body.position.1; - self.context = ParserContext::None; + self.mode = ParserMode::None; Ok(Node::new( Statement::If { @@ -676,6 +693,29 @@ impl<'src> Parser<'src> { left_position, )) } + (Token::Mut, left_position) => { + self.next_token()?; + + let identifier = self.parse_identifier()?; + + if let (Token::Equal, _) = self.current { + self.next_token()?; + } else { + return Err(ParseError::ExpectedToken { + expected: TokenKind::Equal, + actual: self.current.0.to_owned(), + position: self.current.1, + }); + } + + let value = Box::new(self.parse_statement(0)?); + let value_end = value.position.1; + + Ok(Node::new( + Statement::MutAssignment { identifier, value }, + (left_position.0, value_end), + )) + } (Token::Struct, left_position) => { self.next_token()?; @@ -769,7 +809,7 @@ impl<'src> Parser<'src> { (Token::While, left_position) => { self.next_token()?; - let condition = self.parse_statement(0)?; + let condition = self.parse_statement_in_mode(ParserMode::Condition, 0)?; let body = self.parse_block()?; let body_end = body.position.1; @@ -790,6 +830,8 @@ impl<'src> Parser<'src> { } fn parse_infix(&mut self, left: Node) -> Result, ParseError> { + log::trace!("Parsing {} as infix operator", self.current.0); + let operator_precedence = self.current.0.precedence() - if self.current.0.is_right_associative() { 1 @@ -935,6 +977,8 @@ impl<'src> Parser<'src> { } fn parse_postfix(&mut self, left: Node) -> Result, ParseError> { + log::trace!("Parsing {} as postfix operator", self.current.0); + let left_start = left.position.0; let statement = match &self.current.0 { @@ -1095,8 +1139,9 @@ impl<'src> Parser<'src> { } } -enum ParserContext { - IfElseStatement, +#[derive(Debug, PartialEq, Clone, Copy)] +enum ParserMode { + Condition, None, } @@ -1219,9 +1264,8 @@ mod tests { parse(input), Ok(AbstractSyntaxTree { nodes: [Node::new( - Statement::Assignment { + Statement::MutAssignment { identifier: Node::new(Identifier::new("x"), (4, 5)), - operator: Node::new(AssignmentOperator::Assign, (6, 7)), value: Box::new(Node::new( Statement::Constant(Value::integer(42)), (8, 10) @@ -1278,7 +1322,12 @@ mod tests { #[test] fn tuple_struct_access() { - let input = "Foo(42, 'bar').0"; + let input = "(Foo(42, 'bar')).0"; + let mut tree = AbstractSyntaxTree::new(); + + if parse_into(input, &mut tree).is_err() { + println!("{tree:?}") + } assert_eq!( parse(input), @@ -1289,23 +1338,23 @@ mod tests { Statement::Invokation { invokee: Box::new(Node::new( Statement::Identifier(Identifier::new("Foo")), - (0, 3) + (1, 4) )), type_arguments: None, value_arguments: Some(vec![ - Node::new(Statement::Constant(Value::integer(42)), (4, 6)), - Node::new(Statement::Constant(Value::string("bar")), (8, 11)) + Node::new(Statement::Constant(Value::integer(42)), (5, 7)), + Node::new(Statement::Constant(Value::string("bar")), (9, 14)) ]), }, - (0, 12) + (0, 16) )), - operator: Node::new(BinaryOperator::FieldAccess, (13, 14)), + operator: Node::new(BinaryOperator::FieldAccess, (16, 17)), right: Box::new(Node::new( Statement::Constant(Value::integer(0)), - (15, 16) + (17, 18) )) }, - (0, 16) + (0, 18) )] .into() }) diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index b263301..9920a42 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -95,6 +95,31 @@ impl Value { Value::Mutable(Arc::new(RwLock::new(ValueData::Boolean(boolean)))) } + pub fn to_mut(self) -> Self { + match self { + Value::Immutable(inner) => { + Value::Mutable(Arc::new(RwLock::new(inner.as_ref().clone()))) + } + _ => self, + } + } + + pub fn mutate(&self, other: &Value) -> Result<(), VmError> { + let other_data = match other { + Value::Immutable(inner) => inner.as_ref().clone(), + Value::Mutable(inner_locked) => inner_locked.read().unwrap().clone(), + }; + + match self { + Value::Mutable(locked) => { + *locked.write().unwrap() = other_data; + + Ok(()) + } + Value::Immutable(_) => todo!(), + } + } + pub fn r#type(&self) -> Type { match self { Value::Immutable(inner) => inner.r#type(), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index f4addd7..ed3732e 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -360,7 +360,7 @@ impl Vm { Ok(function_call_return) } - Statement::Constant(value) => Ok(Some(value.clone())), + Statement::Constant(value) => Ok(Some(value)), Statement::FieldsStructInstantiation { name, fields } => { let mut values = Vec::new(); @@ -649,6 +649,18 @@ impl Vm { Ok(Some(Value::map(values))) } + Statement::MutAssignment { identifier, value } => { + let position = value.position; + let value = if let Some(value) = self.run_statement(*value)? { + value.to_mut() + } else { + return Err(VmError::ExpectedValue { position }); + }; + + self.context.set_value(identifier.inner, value); + + Ok(None) + } Statement::Nil(node) => { let _return = self.run_statement(*node)?;