From 5757f52dbde37095fb059cdc4659a2007b9a962f Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 13 Aug 2024 17:34:45 -0400 Subject: [PATCH] Refactor to move assingment out of other binary operations --- dust-lang/src/abstract_tree.rs | 49 ++++++-- dust-lang/src/analyzer.rs | 39 +++--- dust-lang/src/lib.rs | 4 +- dust-lang/src/parser.rs | 220 +++++++++++++++------------------ dust-lang/src/token.rs | 8 ++ dust-lang/src/vm.rs | 125 ++++++++----------- 6 files changed, 219 insertions(+), 226 deletions(-) diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index 0b465ac..7cd22ef 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -34,6 +34,12 @@ impl Display for Node { #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Statement { + Assignment { + identifier: Node, + operator: Node, + value: Box>, + }, + // A sequence of statements Block(Vec>), @@ -99,7 +105,7 @@ pub enum Statement { // Value collection expressions List(Vec>), - Map(Vec<(Node, Node)>), + Map(Vec<(Node, Node)>), // Hard-coded value Constant(Value), @@ -112,6 +118,7 @@ pub enum Statement { impl Statement { pub fn expected_type(&self, context: &Context) -> Option { match self { + Statement::Assignment { .. } => None, Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context), Statement::BinaryOperation { left, @@ -132,8 +139,6 @@ impl Statement { | BinaryOperator::And | BinaryOperator::Or => Some(Type::Boolean), - BinaryOperator::Assign | BinaryOperator::AddAssign => None, - BinaryOperator::FieldAccess => { let left_type = left.inner.expected_type(context)?; @@ -180,9 +185,7 @@ impl Statement { let mut types = BTreeMap::new(); for (identifier, item) in nodes { - if let Statement::Identifier(identifier) = &identifier.inner { - types.insert(identifier.clone(), item.inner.expected_type(context)?); - } + types.insert(identifier.inner.clone(), item.inner.expected_type(context)?); } Some(Type::Map(types)) @@ -215,7 +218,7 @@ impl Statement { } } - pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node, Node)>> { + pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node, Node)>> { match self { Statement::Map(properties) => Some(properties), _ => None, @@ -226,6 +229,13 @@ impl Statement { impl Display for Statement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Statement::Assignment { + identifier, + operator, + value, + } => { + write!(f, "{identifier} {operator} {value}") + } Statement::Block(statements) => { write!(f, "{{ ")?; @@ -248,8 +258,6 @@ impl Display for Statement { BinaryOperator::FieldAccess => return write!(f, "{left}.{right}"), BinaryOperator::ListIndex => return write!(f, "{left}[{right}]"), BinaryOperator::Add => "+", - BinaryOperator::AddAssign => "+=", - BinaryOperator::Assign => "=", BinaryOperator::Divide => "/", BinaryOperator::Equal => "==", BinaryOperator::Greater => ">", @@ -422,6 +430,25 @@ impl Display for Statement { } } +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum AssignmentOperator { + Assign, + AddAssign, + SubtractAssign, +} + +impl Display for AssignmentOperator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let operator = match self { + AssignmentOperator::Assign => "=", + AssignmentOperator::AddAssign => "+=", + AssignmentOperator::SubtractAssign => "-=", + }; + + write!(f, "{operator}") + } +} + #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum BinaryOperator { // Accessors @@ -445,10 +472,6 @@ pub enum BinaryOperator { // Logic And, Or, - - // Assignment - Assign, - AddAssign, } #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index ed939f8..9049fd3 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -75,28 +75,29 @@ impl<'a> Analyzer<'a> { fn analyze_statement(&mut self, node: &Node) -> Result<(), AnalyzerError> { match &node.inner { + Statement::Assignment { + 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(), + }); + } + + return Ok(()); + } Statement::BinaryOperation { left, operator, right, } => { - if let BinaryOperator::Assign | BinaryOperator::AddAssign = operator.inner { - self.analyze_statement(right)?; - - if let Statement::Identifier(identifier) = &left.inner { - let right_type = right.inner.expected_type(self.context).ok_or( - AnalyzerError::ExpectedValue { - actual: right.as_ref().clone(), - }, - )?; - - self.context - .set_type(identifier.clone(), right_type, left.position); - - return Ok(()); - } - } - if let BinaryOperator::FieldAccess = operator.inner { self.analyze_statement(left)?; @@ -738,7 +739,7 @@ mod tests { identifier: Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)), statement: Node::new( Statement::Map(vec![( - Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)), + Node::new(Identifier::new("x"), (2, 3)), Node::new(Statement::Constant(Value::integer(1)), (6, 7)) )]), (0, 9) @@ -760,7 +761,7 @@ mod tests { identifier: Node::new(Statement::Constant(Value::string("y")), (10, 13)), statement: Node::new( Statement::Map(vec![( - Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)), + Node::new(Identifier::new("x"), (2, 3)), Node::new(Statement::Constant(Value::integer(1)), (6, 7)) )]), (0, 9) diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index af55715..2a4deff 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -15,8 +15,8 @@ pub mod value; pub mod vm; pub use abstract_tree::{ - AbstractSyntaxTree, BinaryOperator, Node, Statement, StructDefinition, StructInstantiation, - UnaryOperator, + AbstractSyntaxTree, AssignmentOperator, BinaryOperator, Node, Statement, StructDefinition, + StructInstantiation, UnaryOperator, }; pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 3085cf2..06b6b56 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -12,9 +12,9 @@ use std::{ }; use crate::{ - AbstractSyntaxTree, BinaryOperator, BuiltInFunction, DustError, Identifier, LexError, Lexer, - Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, UnaryOperator, - Value, + AbstractSyntaxTree, AssignmentOperator, BinaryOperator, BuiltInFunction, DustError, Identifier, + LexError, Lexer, Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, + UnaryOperator, Value, }; /// Parses the input into an abstract syntax tree. @@ -22,7 +22,7 @@ use crate::{ /// # Examples /// ``` /// # use dust_lang::*; -/// let tree = parse("x = 42").unwrap(); +/// let tree = parse("x + 42").unwrap(); /// /// assert_eq!( /// tree, @@ -35,7 +35,7 @@ use crate::{ /// (0, 1), /// )), /// operator: Node::new( -/// BinaryOperator::Assign, +/// BinaryOperator::Add, /// (2, 3) /// ), /// right: Box::new(Node::new( @@ -93,28 +93,8 @@ pub fn parse(source: &str) -> Result { /// } /// } /// -/// assert_eq!( -/// nodes, -/// Into::>>::into([ -/// Node::new( -/// Statement::BinaryOperation { -/// left: Box::new(Node::new( -/// Statement::Identifier(Identifier::new("x")), -/// (0, 1), -/// )), -/// operator: Node::new( -/// BinaryOperator::Assign, -/// (2, 3), -/// ), -/// right: Box::new(Node::new( -/// Statement::Constant(Value::integer(42)), -/// (4, 6), -/// )), -/// }, -/// (0, 6), -/// ) -/// ]), -/// ); +/// let tree = AbstractSyntaxTree { nodes }; +/// /// ``` pub struct Parser<'src> { source: &'src str, @@ -382,14 +362,14 @@ impl<'src> Parser<'src> { // Determine whether the new statement is a block or a map // // If the first node is an assignment, this might be a map - let mut statement = if let Statement::BinaryOperation { - left, + let mut statement = if let Statement::Assignment { + identifier: left, operator: Node { - inner: BinaryOperator::Assign, - .. + inner: AssignmentOperator::Assign, + position: operator_position, }, - right, + value: right, } = first_node.inner { // If the current token is a comma or closing brace @@ -400,14 +380,14 @@ impl<'src> Parser<'src> { } // The new statement is a map - Statement::Map(vec![(*left, *right)]) + Statement::Map(vec![(left, *right)]) } else { // Otherwise, the new statement is a block Statement::Block(vec![Node::new( - Statement::BinaryOperation { - left, - operator: Node::new(BinaryOperator::Assign, (0, 0)), - right, + Statement::Assignment { + identifier: left, + operator: Node::new(AssignmentOperator::Assign, operator_position), + value: right, }, first_node.position, )]) @@ -437,18 +417,18 @@ impl<'src> Parser<'src> { // If the new statement is already a map if let Some(map_properties) = statement.map_properties_mut() { // Expect the next node to be an assignment - if let Statement::BinaryOperation { - left, + if let Statement::Assignment { + identifier, operator: Node { - inner: BinaryOperator::Assign, + inner: AssignmentOperator::Assign, .. }, - right, + value, } = next_node.inner { // Add the new property to the map - map_properties.push((*left, *right)); + map_properties.push((identifier, *value)); // Allow commas after properties if let Token::Comma = self.current.0 { @@ -654,6 +634,39 @@ impl<'src> Parser<'src> { }; let left_start = left.position.0; + if let Token::Equal | Token::PlusEqual | Token::MinusEqual = &self.current.0 { + let operator_position = self.current.1; + let operator = match self.current.0 { + Token::Equal => AssignmentOperator::Assign, + Token::PlusEqual => AssignmentOperator::AddAssign, + Token::MinusEqual => AssignmentOperator::SubtractAssign, + _ => unreachable!(), + }; + + self.next_token()?; + + let identifier = if let Statement::Identifier(identifier) = left.inner { + Node::new(identifier, left.position) + } else { + return Err(ParseError::ExpectedToken { + expected: TokenKind::Identifier, + actual: self.current.0.to_owned(), + position: self.current.1, + }); + }; + let right = self.parse_statement(operator_precedence)?; + let right_end = right.position.1; + + return Ok(Node::new( + Statement::Assignment { + identifier, + operator: Node::new(operator, operator_position), + value: Box::new(right), + }, + (left_start, right_end), + )); + } + if let Token::Dot = &self.current.0 { let operator_position = self.current.1; @@ -724,14 +737,12 @@ impl<'src> Parser<'src> { Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1), Token::DoubleEqual => Node::new(BinaryOperator::Equal, self.current.1), Token::DoublePipe => Node::new(BinaryOperator::Or, self.current.1), - Token::Equal => Node::new(BinaryOperator::Assign, self.current.1), Token::Greater => Node::new(BinaryOperator::Greater, self.current.1), Token::GreaterEqual => Node::new(BinaryOperator::GreaterOrEqual, self.current.1), Token::Less => Node::new(BinaryOperator::Less, self.current.1), Token::LessEqual => Node::new(BinaryOperator::LessOrEqual, self.current.1), Token::Minus => Node::new(BinaryOperator::Subtract, self.current.1), Token::Plus => Node::new(BinaryOperator::Add, self.current.1), - Token::PlusEqual => Node::new(BinaryOperator::AddAssign, self.current.1), Token::Star => Node::new(BinaryOperator::Multiply, self.current.1), Token::Slash => Node::new(BinaryOperator::Divide, self.current.1), Token::Percent => Node::new(BinaryOperator::Modulo, self.current.1), @@ -1168,16 +1179,10 @@ mod tests { Statement::BinaryOperation { left: Box::new(Node::new( Statement::Map(vec![( - Node::new( - Statement::Identifier(Identifier::new("x")), - (2, 3) - ), + Node::new(Identifier::new("x"), (2, 3)), Node::new( Statement::Map(vec![( - Node::new( - Statement::Identifier(Identifier::new("y")), - (8, 9) - ), + Node::new(Identifier::new("y"), (8, 9)), Node::new( Statement::Constant(Value::integer(42)), (12, 14) @@ -1231,13 +1236,10 @@ mod tests { nodes: [ Node::new( Statement::Nil(Box::new(Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("a")), - (0, 1) - )), - operator: Node::new(BinaryOperator::Assign, (2, 3)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("a"), (0, 1)), + operator: Node::new(AssignmentOperator::Assign, (2, 3)), + value: Box::new(Node::new( Statement::Constant(Value::integer(1)), (4, 5) )), @@ -1336,13 +1338,10 @@ mod tests { nodes: [ Node::new( Statement::Nil(Box::new(Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("a")), - (0, 1) - )), - operator: Node::new(BinaryOperator::Assign, (2, 3)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("a"), (0, 1)), + operator: Node::new(AssignmentOperator::Assign, (2, 3)), + value: Box::new(Node::new( Statement::Constant(Value::boolean(false)), (4, 9) )), @@ -1486,13 +1485,10 @@ mod tests { parse_error: ParseError::ExpectedAssignment { actual: Node::new( Statement::Nil(Box::new(Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("z")), - (16, 17) - )), - operator: Node::new(BinaryOperator::Assign, (18, 19)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("z"), (16, 17)), + operator: Node::new(AssignmentOperator::Assign, (18, 19)), + value: Box::new(Node::new( Statement::Constant(Value::integer(3)), (20, 21) )), @@ -1531,13 +1527,10 @@ mod tests { )), body: Box::new(Node::new( Statement::Block(vec![Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("x")), - (15, 16) - )), - operator: Node::new(BinaryOperator::AddAssign, (17, 19)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("x"), (15, 16)), + operator: Node::new(AssignmentOperator::AddAssign, (17, 19)), + value: Box::new(Node::new( Statement::Constant(Value::integer(1)), (20, 21) )), @@ -1562,13 +1555,10 @@ mod tests { parse(input), Ok(AbstractSyntaxTree { nodes: [Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("a")), - (0, 1) - )), - operator: Node::new(BinaryOperator::AddAssign, (2, 4)), - right: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))), + Statement::Assignment { + identifier: Node::new(Identifier::new("a"), (0, 1)), + operator: Node::new(AssignmentOperator::AddAssign, (2, 4)), + value: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))), }, (0, 6) )] @@ -1659,13 +1649,10 @@ mod tests { Statement::Block(vec![ Node::new( Statement::Nil(Box::new(Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("foo")), - (2, 5) - )), - operator: Node::new(BinaryOperator::Assign, (6, 7)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("foo"), (2, 5)), + operator: Node::new(AssignmentOperator::Assign, (6, 7)), + value: Box::new(Node::new( Statement::Constant(Value::integer(42)), (8, 10) )), @@ -1676,13 +1663,10 @@ mod tests { ), Node::new( Statement::Nil(Box::new(Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("bar")), - (12, 15) - )), - operator: Node::new(BinaryOperator::Assign, (16, 17)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("bar"), (12, 15)), + operator: Node::new(AssignmentOperator::Assign, (16, 17)), + value: Box::new(Node::new( Statement::Constant(Value::integer(42)), (18, 20) )), @@ -1692,13 +1676,10 @@ mod tests { (12, 21) ), Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("baz")), - (22, 25) - )), - operator: Node::new(BinaryOperator::Assign, (26, 27)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("baz"), (22, 25)), + operator: Node::new(AssignmentOperator::Assign, (26, 27)), + value: Box::new(Node::new( Statement::Constant(Value::string("42")), (28, 32) )), @@ -1735,15 +1716,15 @@ mod tests { nodes: [Node::new( Statement::Map(vec![ ( - Node::new(Statement::Identifier(Identifier::new("foo")), (2, 5)), + Node::new(Identifier::new("foo"), (2, 5)), Node::new(Statement::Constant(Value::integer(42)), (8, 10)) ), ( - Node::new(Statement::Identifier(Identifier::new("bar")), (12, 15)), + Node::new(Identifier::new("bar"), (12, 15)), Node::new(Statement::Constant(Value::integer(42)), (18, 20)) ), ( - Node::new(Statement::Identifier(Identifier::new("baz")), (22, 25)), + Node::new(Identifier::new("baz"), (22, 25)), Node::new(Statement::Constant(Value::string("42")), (28, 32)) ), ]), @@ -1764,11 +1745,11 @@ mod tests { nodes: [Node::new( Statement::Map(vec![ ( - Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)), + Node::new(Identifier::new("x"), (2, 3)), Node::new(Statement::Constant(Value::integer(42)), (6, 8)) ), ( - Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)), + Node::new(Identifier::new("y"), (10, 11)), Node::new(Statement::Constant(Value::string("foobar")), (14, 22)) ) ]), @@ -1788,7 +1769,7 @@ mod tests { Ok(AbstractSyntaxTree { nodes: [Node::new( Statement::Map(vec![( - Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)), + Node::new(Identifier::new("x"), (2, 3)), Node::new(Statement::Constant(Value::integer(42)), (6, 8)) )]), (0, 10) @@ -2271,13 +2252,10 @@ mod tests { parse(input), Ok(AbstractSyntaxTree { nodes: [Node::new( - Statement::BinaryOperation { - left: Box::new(Node::new( - Statement::Identifier(Identifier::new("a")), - (0, 1) - )), - operator: Node::new(BinaryOperator::Assign, (2, 3)), - right: Box::new(Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("a"), (0, 1)), + operator: Node::new(AssignmentOperator::Assign, (2, 3)), + value: Box::new(Node::new( Statement::BinaryOperation { left: Box::new(Node::new( Statement::Constant(Value::integer(1)), diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index ecd1c7a..3206e74 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -50,6 +50,7 @@ pub enum Token<'src> { Less, LessEqual, Minus, + MinusEqual, Percent, Plus, PlusEqual, @@ -94,6 +95,7 @@ impl<'src> Token<'src> { Token::Less => TokenOwned::Less, Token::LessEqual => TokenOwned::LessOrEqual, Token::Minus => TokenOwned::Minus, + Token::MinusEqual => TokenOwned::MinusEqual, Token::Percent => TokenOwned::Percent, Token::Plus => TokenOwned::Plus, Token::PlusEqual => TokenOwned::PlusEqual, @@ -147,6 +149,7 @@ impl<'src> Token<'src> { Token::Less => "<", Token::LessEqual => "<=", Token::Minus => "-", + Token::MinusEqual => "-=", Token::Percent => "%", Token::Plus => "+", Token::PlusEqual => "+=", @@ -197,6 +200,7 @@ impl<'src> Token<'src> { Token::Less => TokenKind::Less, Token::LessEqual => TokenKind::LessOrEqual, Token::Minus => TokenKind::Minus, + Token::MinusEqual => TokenKind::MinusEqual, Token::Percent => TokenKind::Percent, Token::Plus => TokenKind::Plus, Token::PlusEqual => TokenKind::PlusEqual, @@ -322,6 +326,7 @@ pub enum TokenOwned { Less, LessOrEqual, Minus, + MinusEqual, Percent, Plus, PlusEqual, @@ -367,6 +372,7 @@ impl Display for TokenOwned { TokenOwned::Less => Token::Less.fmt(f), TokenOwned::LessOrEqual => Token::LessEqual.fmt(f), TokenOwned::Minus => Token::Minus.fmt(f), + TokenOwned::MinusEqual => Token::MinusEqual.fmt(f), TokenOwned::Percent => Token::Percent.fmt(f), TokenOwned::Plus => Token::Plus.fmt(f), TokenOwned::PlusEqual => Token::PlusEqual.fmt(f), @@ -433,6 +439,7 @@ pub enum TokenKind { Less, LessOrEqual, Minus, + MinusEqual, Percent, Plus, PlusEqual, @@ -478,6 +485,7 @@ impl Display for TokenKind { TokenKind::Less => Token::Less.fmt(f), TokenKind::LessOrEqual => Token::LessEqual.fmt(f), TokenKind::Minus => Token::Minus.fmt(f), + TokenKind::MinusEqual => Token::MinusEqual.fmt(f), TokenKind::Percent => Token::Percent.fmt(f), TokenKind::Plus => Token::Plus.fmt(f), TokenKind::PlusEqual => Token::PlusEqual.fmt(f), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index b66ec4c..f8b46c3 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -10,9 +10,10 @@ use std::{ }; use crate::{ - parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError, - Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructDefinition, - StructInstantiation, StructType, Type, UnaryOperator, Value, ValueError, + parse, value::ValueInner, AbstractSyntaxTree, Analyzer, AssignmentOperator, BinaryOperator, + BuiltInFunctionError, Context, DustError, Identifier, Node, ParseError, Span, Statement, + Struct, StructDefinition, StructInstantiation, StructType, Type, UnaryOperator, Value, + ValueError, }; /// Run the source code and return the result. @@ -96,6 +97,53 @@ impl Vm { fn run_statement(&self, node: Node) -> Result, VmError> { match node.inner { + Statement::Assignment { + identifier, + operator, + value, + } => match operator.inner { + AssignmentOperator::Assign => { + let position = value.position; + let value = if let Some(value) = self.run_statement(*value)? { + value + } else { + return Err(VmError::ExpectedValue { position }); + }; + + self.context.set_value(identifier.inner, value); + + Ok(None) + } + AssignmentOperator::AddAssign => { + let left_value = if let Some(value) = self.context.get_value(&identifier.inner) + { + value + } else { + return Err(VmError::UndefinedVariable { identifier }); + }; + let value_position = value.position; + let right_value = if let Some(value) = self.run_statement(*value)? { + value + } else { + return Err(VmError::ExpectedValue { + position: value_position, + }); + }; + let new_value = left_value.add(&right_value).map_err(|value_error| { + VmError::ValueError { + error: value_error, + position: (identifier.position.0, value_position.1), + } + })?; + + self.context.set_value(identifier.inner, new_value); + + Ok(None) + } + AssignmentOperator::SubtractAssign => { + todo!() + } + }, Statement::BinaryOperation { left, operator, @@ -103,64 +151,6 @@ impl Vm { } => { let right_position = right.position; - if let BinaryOperator::Assign = operator.inner { - let identifier = if let Statement::Identifier(identifier) = left.inner { - identifier - } else { - return Err(VmError::ExpectedIdentifier { - position: left.position, - }); - }; - let value = if let Some(value) = self.run_statement(*right)? { - value - } else { - return Err(VmError::ExpectedValue { - position: right_position, - }); - }; - - self.context.set_value(identifier, value); - - return Ok(None); - } - - if let BinaryOperator::AddAssign = operator.inner { - let (identifier, left_value) = - if let Statement::Identifier(identifier) = left.inner { - let value = self.context.get_value(&identifier).ok_or_else(|| { - VmError::UndefinedVariable { - identifier: Node::new( - Statement::Identifier(identifier.clone()), - left.position, - ), - } - })?; - - (identifier, value) - } else { - return Err(VmError::ExpectedIdentifier { - position: left.position, - }); - }; - let right_value = if let Some(value) = self.run_statement(*right)? { - value - } else { - return Err(VmError::ExpectedValue { - position: right_position, - }); - }; - let new_value = left_value.add(&right_value).map_err(|value_error| { - VmError::ValueError { - error: value_error, - position: right_position, - } - })?; - - self.context.set_value(identifier, new_value); - - return Ok(None); - } - if let BinaryOperator::FieldAccess = operator.inner { let left_span = left.position; let left_value = if let Some(value) = self.run_statement(*left)? { @@ -416,7 +406,7 @@ impl Vm { } Err(VmError::UndefinedVariable { - identifier: Node::new(Statement::Identifier(identifier), node.position), + identifier: Node::new(identifier, node.position), }) } Statement::If { condition, body } => { @@ -586,13 +576,6 @@ impl Vm { let mut values = BTreeMap::new(); for (identifier, value_node) in nodes { - let identifier = if let Statement::Identifier(identifier) = identifier.inner { - identifier - } else { - return Err(VmError::ExpectedIdentifier { - position: identifier.position, - }); - }; let position = value_node.position; let value = if let Some(value) = self.run_statement(value_node)? { value @@ -600,7 +583,7 @@ impl Vm { return Err(VmError::ExpectedValue { position }); }; - values.insert(identifier, value); + values.insert(identifier.inner, value); } Ok(Some(Value::map(values))) @@ -754,7 +737,7 @@ pub enum VmError { position: Span, }, UndefinedVariable { - identifier: Node, + identifier: Node, }, UndefinedProperty { value: Value,