Refactor to move assingment out of other binary operations

This commit is contained in:
Jeff 2024-08-13 17:34:45 -04:00
parent b1337900fb
commit 5757f52dbd
6 changed files with 219 additions and 226 deletions

View File

@ -34,6 +34,12 @@ impl<T: Display> Display for Node<T> {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Statement { pub enum Statement {
Assignment {
identifier: Node<Identifier>,
operator: Node<AssignmentOperator>,
value: Box<Node<Statement>>,
},
// A sequence of statements // A sequence of statements
Block(Vec<Node<Statement>>), Block(Vec<Node<Statement>>),
@ -99,7 +105,7 @@ pub enum Statement {
// Value collection expressions // Value collection expressions
List(Vec<Node<Statement>>), List(Vec<Node<Statement>>),
Map(Vec<(Node<Statement>, Node<Statement>)>), Map(Vec<(Node<Identifier>, Node<Statement>)>),
// Hard-coded value // Hard-coded value
Constant(Value), Constant(Value),
@ -112,6 +118,7 @@ pub enum Statement {
impl Statement { impl Statement {
pub fn expected_type(&self, context: &Context) -> Option<Type> { pub fn expected_type(&self, context: &Context) -> Option<Type> {
match self { match self {
Statement::Assignment { .. } => None,
Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context), Statement::Block(nodes) => nodes.last().unwrap().inner.expected_type(context),
Statement::BinaryOperation { Statement::BinaryOperation {
left, left,
@ -132,8 +139,6 @@ impl Statement {
| BinaryOperator::And | BinaryOperator::And
| BinaryOperator::Or => Some(Type::Boolean), | BinaryOperator::Or => Some(Type::Boolean),
BinaryOperator::Assign | BinaryOperator::AddAssign => None,
BinaryOperator::FieldAccess => { BinaryOperator::FieldAccess => {
let left_type = left.inner.expected_type(context)?; let left_type = left.inner.expected_type(context)?;
@ -180,9 +185,7 @@ impl Statement {
let mut types = BTreeMap::new(); let mut types = BTreeMap::new();
for (identifier, item) in nodes { for (identifier, item) in nodes {
if let Statement::Identifier(identifier) = &identifier.inner { types.insert(identifier.inner.clone(), item.inner.expected_type(context)?);
types.insert(identifier.clone(), item.inner.expected_type(context)?);
}
} }
Some(Type::Map(types)) Some(Type::Map(types))
@ -215,7 +218,7 @@ impl Statement {
} }
} }
pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node<Statement>, Node<Statement>)>> { pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node<Identifier>, Node<Statement>)>> {
match self { match self {
Statement::Map(properties) => Some(properties), Statement::Map(properties) => Some(properties),
_ => None, _ => None,
@ -226,6 +229,13 @@ impl Statement {
impl Display for Statement { impl Display for Statement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Statement::Assignment {
identifier,
operator,
value,
} => {
write!(f, "{identifier} {operator} {value}")
}
Statement::Block(statements) => { Statement::Block(statements) => {
write!(f, "{{ ")?; write!(f, "{{ ")?;
@ -248,8 +258,6 @@ impl Display for Statement {
BinaryOperator::FieldAccess => return write!(f, "{left}.{right}"), BinaryOperator::FieldAccess => return write!(f, "{left}.{right}"),
BinaryOperator::ListIndex => return write!(f, "{left}[{right}]"), BinaryOperator::ListIndex => return write!(f, "{left}[{right}]"),
BinaryOperator::Add => "+", BinaryOperator::Add => "+",
BinaryOperator::AddAssign => "+=",
BinaryOperator::Assign => "=",
BinaryOperator::Divide => "/", BinaryOperator::Divide => "/",
BinaryOperator::Equal => "==", BinaryOperator::Equal => "==",
BinaryOperator::Greater => ">", 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)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BinaryOperator { pub enum BinaryOperator {
// Accessors // Accessors
@ -445,10 +472,6 @@ pub enum BinaryOperator {
// Logic // Logic
And, And,
Or, Or,
// Assignment
Assign,
AddAssign,
} }
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]

View File

@ -75,28 +75,29 @@ impl<'a> Analyzer<'a> {
fn analyze_statement(&mut self, node: &Node<Statement>) -> Result<(), AnalyzerError> { fn analyze_statement(&mut self, node: &Node<Statement>) -> Result<(), AnalyzerError> {
match &node.inner { 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 { Statement::BinaryOperation {
left, left,
operator, operator,
right, 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 { if let BinaryOperator::FieldAccess = operator.inner {
self.analyze_statement(left)?; self.analyze_statement(left)?;
@ -738,7 +739,7 @@ mod tests {
identifier: Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)), identifier: Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)),
statement: Node::new( statement: Node::new(
Statement::Map(vec![( 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)) Node::new(Statement::Constant(Value::integer(1)), (6, 7))
)]), )]),
(0, 9) (0, 9)
@ -760,7 +761,7 @@ mod tests {
identifier: Node::new(Statement::Constant(Value::string("y")), (10, 13)), identifier: Node::new(Statement::Constant(Value::string("y")), (10, 13)),
statement: Node::new( statement: Node::new(
Statement::Map(vec![( 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)) Node::new(Statement::Constant(Value::integer(1)), (6, 7))
)]), )]),
(0, 9) (0, 9)

View File

@ -15,8 +15,8 @@ pub mod value;
pub mod vm; pub mod vm;
pub use abstract_tree::{ pub use abstract_tree::{
AbstractSyntaxTree, BinaryOperator, Node, Statement, StructDefinition, StructInstantiation, AbstractSyntaxTree, AssignmentOperator, BinaryOperator, Node, Statement, StructDefinition,
UnaryOperator, StructInstantiation, UnaryOperator,
}; };
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};

View File

@ -12,9 +12,9 @@ use std::{
}; };
use crate::{ use crate::{
AbstractSyntaxTree, BinaryOperator, BuiltInFunction, DustError, Identifier, LexError, Lexer, AbstractSyntaxTree, AssignmentOperator, BinaryOperator, BuiltInFunction, DustError, Identifier,
Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, UnaryOperator, LexError, Lexer, Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type,
Value, UnaryOperator, Value,
}; };
/// Parses the input into an abstract syntax tree. /// Parses the input into an abstract syntax tree.
@ -22,7 +22,7 @@ use crate::{
/// # Examples /// # Examples
/// ``` /// ```
/// # use dust_lang::*; /// # use dust_lang::*;
/// let tree = parse("x = 42").unwrap(); /// let tree = parse("x + 42").unwrap();
/// ///
/// assert_eq!( /// assert_eq!(
/// tree, /// tree,
@ -35,7 +35,7 @@ use crate::{
/// (0, 1), /// (0, 1),
/// )), /// )),
/// operator: Node::new( /// operator: Node::new(
/// BinaryOperator::Assign, /// BinaryOperator::Add,
/// (2, 3) /// (2, 3)
/// ), /// ),
/// right: Box::new(Node::new( /// right: Box::new(Node::new(
@ -93,28 +93,8 @@ pub fn parse(source: &str) -> Result<AbstractSyntaxTree, DustError> {
/// } /// }
/// } /// }
/// ///
/// assert_eq!( /// let tree = AbstractSyntaxTree { nodes };
/// nodes, ///
/// Into::<VecDeque<Node<Statement>>>::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),
/// )
/// ]),
/// );
/// ``` /// ```
pub struct Parser<'src> { pub struct Parser<'src> {
source: &'src str, source: &'src str,
@ -382,14 +362,14 @@ impl<'src> Parser<'src> {
// Determine whether the new statement is a block or a map // Determine whether the new statement is a block or a map
// //
// If the first node is an assignment, this might be a map // If the first node is an assignment, this might be a map
let mut statement = if let Statement::BinaryOperation { let mut statement = if let Statement::Assignment {
left, identifier: left,
operator: operator:
Node { Node {
inner: BinaryOperator::Assign, inner: AssignmentOperator::Assign,
.. position: operator_position,
}, },
right, value: right,
} = first_node.inner } = first_node.inner
{ {
// If the current token is a comma or closing brace // If the current token is a comma or closing brace
@ -400,14 +380,14 @@ impl<'src> Parser<'src> {
} }
// The new statement is a map // The new statement is a map
Statement::Map(vec![(*left, *right)]) Statement::Map(vec![(left, *right)])
} else { } else {
// Otherwise, the new statement is a block // Otherwise, the new statement is a block
Statement::Block(vec![Node::new( Statement::Block(vec![Node::new(
Statement::BinaryOperation { Statement::Assignment {
left, identifier: left,
operator: Node::new(BinaryOperator::Assign, (0, 0)), operator: Node::new(AssignmentOperator::Assign, operator_position),
right, value: right,
}, },
first_node.position, first_node.position,
)]) )])
@ -437,18 +417,18 @@ impl<'src> Parser<'src> {
// If the new statement is already a map // If the new statement is already a map
if let Some(map_properties) = statement.map_properties_mut() { if let Some(map_properties) = statement.map_properties_mut() {
// Expect the next node to be an assignment // Expect the next node to be an assignment
if let Statement::BinaryOperation { if let Statement::Assignment {
left, identifier,
operator: operator:
Node { Node {
inner: BinaryOperator::Assign, inner: AssignmentOperator::Assign,
.. ..
}, },
right, value,
} = next_node.inner } = next_node.inner
{ {
// Add the new property to the map // Add the new property to the map
map_properties.push((*left, *right)); map_properties.push((identifier, *value));
// Allow commas after properties // Allow commas after properties
if let Token::Comma = self.current.0 { if let Token::Comma = self.current.0 {
@ -654,6 +634,39 @@ impl<'src> Parser<'src> {
}; };
let left_start = left.position.0; 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 { if let Token::Dot = &self.current.0 {
let operator_position = self.current.1; let operator_position = self.current.1;
@ -724,14 +737,12 @@ impl<'src> Parser<'src> {
Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1), Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1),
Token::DoubleEqual => Node::new(BinaryOperator::Equal, self.current.1), Token::DoubleEqual => Node::new(BinaryOperator::Equal, self.current.1),
Token::DoublePipe => Node::new(BinaryOperator::Or, 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::Greater => Node::new(BinaryOperator::Greater, self.current.1),
Token::GreaterEqual => Node::new(BinaryOperator::GreaterOrEqual, self.current.1), Token::GreaterEqual => Node::new(BinaryOperator::GreaterOrEqual, self.current.1),
Token::Less => Node::new(BinaryOperator::Less, self.current.1), Token::Less => Node::new(BinaryOperator::Less, self.current.1),
Token::LessEqual => Node::new(BinaryOperator::LessOrEqual, self.current.1), Token::LessEqual => Node::new(BinaryOperator::LessOrEqual, self.current.1),
Token::Minus => Node::new(BinaryOperator::Subtract, self.current.1), Token::Minus => Node::new(BinaryOperator::Subtract, self.current.1),
Token::Plus => Node::new(BinaryOperator::Add, 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::Star => Node::new(BinaryOperator::Multiply, self.current.1),
Token::Slash => Node::new(BinaryOperator::Divide, self.current.1), Token::Slash => Node::new(BinaryOperator::Divide, self.current.1),
Token::Percent => Node::new(BinaryOperator::Modulo, self.current.1), Token::Percent => Node::new(BinaryOperator::Modulo, self.current.1),
@ -1168,16 +1179,10 @@ mod tests {
Statement::BinaryOperation { Statement::BinaryOperation {
left: Box::new(Node::new( left: Box::new(Node::new(
Statement::Map(vec![( Statement::Map(vec![(
Node::new( Node::new(Identifier::new("x"), (2, 3)),
Statement::Identifier(Identifier::new("x")),
(2, 3)
),
Node::new( Node::new(
Statement::Map(vec![( Statement::Map(vec![(
Node::new( Node::new(Identifier::new("y"), (8, 9)),
Statement::Identifier(Identifier::new("y")),
(8, 9)
),
Node::new( Node::new(
Statement::Constant(Value::integer(42)), Statement::Constant(Value::integer(42)),
(12, 14) (12, 14)
@ -1231,13 +1236,10 @@ mod tests {
nodes: [ nodes: [
Node::new( Node::new(
Statement::Nil(Box::new(Node::new( Statement::Nil(Box::new(Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("a"), (0, 1)),
Statement::Identifier(Identifier::new("a")), operator: Node::new(AssignmentOperator::Assign, (2, 3)),
(0, 1) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (2, 3)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(1)), Statement::Constant(Value::integer(1)),
(4, 5) (4, 5)
)), )),
@ -1336,13 +1338,10 @@ mod tests {
nodes: [ nodes: [
Node::new( Node::new(
Statement::Nil(Box::new(Node::new( Statement::Nil(Box::new(Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("a"), (0, 1)),
Statement::Identifier(Identifier::new("a")), operator: Node::new(AssignmentOperator::Assign, (2, 3)),
(0, 1) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (2, 3)),
right: Box::new(Node::new(
Statement::Constant(Value::boolean(false)), Statement::Constant(Value::boolean(false)),
(4, 9) (4, 9)
)), )),
@ -1486,13 +1485,10 @@ mod tests {
parse_error: ParseError::ExpectedAssignment { parse_error: ParseError::ExpectedAssignment {
actual: Node::new( actual: Node::new(
Statement::Nil(Box::new(Node::new( Statement::Nil(Box::new(Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("z"), (16, 17)),
Statement::Identifier(Identifier::new("z")), operator: Node::new(AssignmentOperator::Assign, (18, 19)),
(16, 17) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (18, 19)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(3)), Statement::Constant(Value::integer(3)),
(20, 21) (20, 21)
)), )),
@ -1531,13 +1527,10 @@ mod tests {
)), )),
body: Box::new(Node::new( body: Box::new(Node::new(
Statement::Block(vec![Node::new( Statement::Block(vec![Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("x"), (15, 16)),
Statement::Identifier(Identifier::new("x")), operator: Node::new(AssignmentOperator::AddAssign, (17, 19)),
(15, 16) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::AddAssign, (17, 19)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(1)), Statement::Constant(Value::integer(1)),
(20, 21) (20, 21)
)), )),
@ -1562,13 +1555,10 @@ mod tests {
parse(input), parse(input),
Ok(AbstractSyntaxTree { Ok(AbstractSyntaxTree {
nodes: [Node::new( nodes: [Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("a"), (0, 1)),
Statement::Identifier(Identifier::new("a")), operator: Node::new(AssignmentOperator::AddAssign, (2, 4)),
(0, 1) value: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))),
)),
operator: Node::new(BinaryOperator::AddAssign, (2, 4)),
right: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))),
}, },
(0, 6) (0, 6)
)] )]
@ -1659,13 +1649,10 @@ mod tests {
Statement::Block(vec![ Statement::Block(vec![
Node::new( Node::new(
Statement::Nil(Box::new(Node::new( Statement::Nil(Box::new(Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("foo"), (2, 5)),
Statement::Identifier(Identifier::new("foo")), operator: Node::new(AssignmentOperator::Assign, (6, 7)),
(2, 5) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (6, 7)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(42)), Statement::Constant(Value::integer(42)),
(8, 10) (8, 10)
)), )),
@ -1676,13 +1663,10 @@ mod tests {
), ),
Node::new( Node::new(
Statement::Nil(Box::new(Node::new( Statement::Nil(Box::new(Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("bar"), (12, 15)),
Statement::Identifier(Identifier::new("bar")), operator: Node::new(AssignmentOperator::Assign, (16, 17)),
(12, 15) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (16, 17)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(42)), Statement::Constant(Value::integer(42)),
(18, 20) (18, 20)
)), )),
@ -1692,13 +1676,10 @@ mod tests {
(12, 21) (12, 21)
), ),
Node::new( Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("baz"), (22, 25)),
Statement::Identifier(Identifier::new("baz")), operator: Node::new(AssignmentOperator::Assign, (26, 27)),
(22, 25) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (26, 27)),
right: Box::new(Node::new(
Statement::Constant(Value::string("42")), Statement::Constant(Value::string("42")),
(28, 32) (28, 32)
)), )),
@ -1735,15 +1716,15 @@ mod tests {
nodes: [Node::new( nodes: [Node::new(
Statement::Map(vec![ 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::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::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)) Node::new(Statement::Constant(Value::string("42")), (28, 32))
), ),
]), ]),
@ -1764,11 +1745,11 @@ mod tests {
nodes: [Node::new( nodes: [Node::new(
Statement::Map(vec![ 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::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)) Node::new(Statement::Constant(Value::string("foobar")), (14, 22))
) )
]), ]),
@ -1788,7 +1769,7 @@ mod tests {
Ok(AbstractSyntaxTree { Ok(AbstractSyntaxTree {
nodes: [Node::new( nodes: [Node::new(
Statement::Map(vec![( 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::Constant(Value::integer(42)), (6, 8))
)]), )]),
(0, 10) (0, 10)
@ -2271,13 +2252,10 @@ mod tests {
parse(input), parse(input),
Ok(AbstractSyntaxTree { Ok(AbstractSyntaxTree {
nodes: [Node::new( nodes: [Node::new(
Statement::BinaryOperation { Statement::Assignment {
left: Box::new(Node::new( identifier: Node::new(Identifier::new("a"), (0, 1)),
Statement::Identifier(Identifier::new("a")), operator: Node::new(AssignmentOperator::Assign, (2, 3)),
(0, 1) value: Box::new(Node::new(
)),
operator: Node::new(BinaryOperator::Assign, (2, 3)),
right: Box::new(Node::new(
Statement::BinaryOperation { Statement::BinaryOperation {
left: Box::new(Node::new( left: Box::new(Node::new(
Statement::Constant(Value::integer(1)), Statement::Constant(Value::integer(1)),

View File

@ -50,6 +50,7 @@ pub enum Token<'src> {
Less, Less,
LessEqual, LessEqual,
Minus, Minus,
MinusEqual,
Percent, Percent,
Plus, Plus,
PlusEqual, PlusEqual,
@ -94,6 +95,7 @@ impl<'src> Token<'src> {
Token::Less => TokenOwned::Less, Token::Less => TokenOwned::Less,
Token::LessEqual => TokenOwned::LessOrEqual, Token::LessEqual => TokenOwned::LessOrEqual,
Token::Minus => TokenOwned::Minus, Token::Minus => TokenOwned::Minus,
Token::MinusEqual => TokenOwned::MinusEqual,
Token::Percent => TokenOwned::Percent, Token::Percent => TokenOwned::Percent,
Token::Plus => TokenOwned::Plus, Token::Plus => TokenOwned::Plus,
Token::PlusEqual => TokenOwned::PlusEqual, Token::PlusEqual => TokenOwned::PlusEqual,
@ -147,6 +149,7 @@ impl<'src> Token<'src> {
Token::Less => "<", Token::Less => "<",
Token::LessEqual => "<=", Token::LessEqual => "<=",
Token::Minus => "-", Token::Minus => "-",
Token::MinusEqual => "-=",
Token::Percent => "%", Token::Percent => "%",
Token::Plus => "+", Token::Plus => "+",
Token::PlusEqual => "+=", Token::PlusEqual => "+=",
@ -197,6 +200,7 @@ impl<'src> Token<'src> {
Token::Less => TokenKind::Less, Token::Less => TokenKind::Less,
Token::LessEqual => TokenKind::LessOrEqual, Token::LessEqual => TokenKind::LessOrEqual,
Token::Minus => TokenKind::Minus, Token::Minus => TokenKind::Minus,
Token::MinusEqual => TokenKind::MinusEqual,
Token::Percent => TokenKind::Percent, Token::Percent => TokenKind::Percent,
Token::Plus => TokenKind::Plus, Token::Plus => TokenKind::Plus,
Token::PlusEqual => TokenKind::PlusEqual, Token::PlusEqual => TokenKind::PlusEqual,
@ -322,6 +326,7 @@ pub enum TokenOwned {
Less, Less,
LessOrEqual, LessOrEqual,
Minus, Minus,
MinusEqual,
Percent, Percent,
Plus, Plus,
PlusEqual, PlusEqual,
@ -367,6 +372,7 @@ impl Display for TokenOwned {
TokenOwned::Less => Token::Less.fmt(f), TokenOwned::Less => Token::Less.fmt(f),
TokenOwned::LessOrEqual => Token::LessEqual.fmt(f), TokenOwned::LessOrEqual => Token::LessEqual.fmt(f),
TokenOwned::Minus => Token::Minus.fmt(f), TokenOwned::Minus => Token::Minus.fmt(f),
TokenOwned::MinusEqual => Token::MinusEqual.fmt(f),
TokenOwned::Percent => Token::Percent.fmt(f), TokenOwned::Percent => Token::Percent.fmt(f),
TokenOwned::Plus => Token::Plus.fmt(f), TokenOwned::Plus => Token::Plus.fmt(f),
TokenOwned::PlusEqual => Token::PlusEqual.fmt(f), TokenOwned::PlusEqual => Token::PlusEqual.fmt(f),
@ -433,6 +439,7 @@ pub enum TokenKind {
Less, Less,
LessOrEqual, LessOrEqual,
Minus, Minus,
MinusEqual,
Percent, Percent,
Plus, Plus,
PlusEqual, PlusEqual,
@ -478,6 +485,7 @@ impl Display for TokenKind {
TokenKind::Less => Token::Less.fmt(f), TokenKind::Less => Token::Less.fmt(f),
TokenKind::LessOrEqual => Token::LessEqual.fmt(f), TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
TokenKind::Minus => Token::Minus.fmt(f), TokenKind::Minus => Token::Minus.fmt(f),
TokenKind::MinusEqual => Token::MinusEqual.fmt(f),
TokenKind::Percent => Token::Percent.fmt(f), TokenKind::Percent => Token::Percent.fmt(f),
TokenKind::Plus => Token::Plus.fmt(f), TokenKind::Plus => Token::Plus.fmt(f),
TokenKind::PlusEqual => Token::PlusEqual.fmt(f), TokenKind::PlusEqual => Token::PlusEqual.fmt(f),

View File

@ -10,9 +10,10 @@ use std::{
}; };
use crate::{ use crate::{
parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError, parse, value::ValueInner, AbstractSyntaxTree, Analyzer, AssignmentOperator, BinaryOperator,
Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructDefinition, BuiltInFunctionError, Context, DustError, Identifier, Node, ParseError, Span, Statement,
StructInstantiation, StructType, Type, UnaryOperator, Value, ValueError, Struct, StructDefinition, StructInstantiation, StructType, Type, UnaryOperator, Value,
ValueError,
}; };
/// Run the source code and return the result. /// Run the source code and return the result.
@ -96,6 +97,53 @@ impl Vm {
fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> { fn run_statement(&self, node: Node<Statement>) -> Result<Option<Value>, VmError> {
match node.inner { 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 { Statement::BinaryOperation {
left, left,
operator, operator,
@ -103,64 +151,6 @@ impl Vm {
} => { } => {
let right_position = right.position; 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 { if let BinaryOperator::FieldAccess = operator.inner {
let left_span = left.position; let left_span = left.position;
let left_value = if let Some(value) = self.run_statement(*left)? { let left_value = if let Some(value) = self.run_statement(*left)? {
@ -416,7 +406,7 @@ impl Vm {
} }
Err(VmError::UndefinedVariable { Err(VmError::UndefinedVariable {
identifier: Node::new(Statement::Identifier(identifier), node.position), identifier: Node::new(identifier, node.position),
}) })
} }
Statement::If { condition, body } => { Statement::If { condition, body } => {
@ -586,13 +576,6 @@ impl Vm {
let mut values = BTreeMap::new(); let mut values = BTreeMap::new();
for (identifier, value_node) in nodes { 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 position = value_node.position;
let value = if let Some(value) = self.run_statement(value_node)? { let value = if let Some(value) = self.run_statement(value_node)? {
value value
@ -600,7 +583,7 @@ impl Vm {
return Err(VmError::ExpectedValue { position }); return Err(VmError::ExpectedValue { position });
}; };
values.insert(identifier, value); values.insert(identifier.inner, value);
} }
Ok(Some(Value::map(values))) Ok(Some(Value::map(values)))
@ -754,7 +737,7 @@ pub enum VmError {
position: Span, position: Span,
}, },
UndefinedVariable { UndefinedVariable {
identifier: Node<Statement>, identifier: Node<Identifier>,
}, },
UndefinedProperty { UndefinedProperty {
value: Value, value: Value,