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)]
pub enum Statement {
Assignment {
identifier: Node<Identifier>,
operator: Node<AssignmentOperator>,
value: Box<Node<Statement>>,
},
// A sequence of statements
Block(Vec<Node<Statement>>),
@ -99,7 +105,7 @@ pub enum Statement {
// Value collection expressions
List(Vec<Node<Statement>>),
Map(Vec<(Node<Statement>, Node<Statement>)>),
Map(Vec<(Node<Identifier>, Node<Statement>)>),
// Hard-coded value
Constant(Value),
@ -112,6 +118,7 @@ pub enum Statement {
impl Statement {
pub fn expected_type(&self, context: &Context) -> Option<Type> {
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<Statement>, Node<Statement>)>> {
pub fn map_properties_mut(&mut self) -> Option<&mut Vec<(Node<Identifier>, Node<Statement>)>> {
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)]

View File

@ -75,28 +75,29 @@ impl<'a> Analyzer<'a> {
fn analyze_statement(&mut self, node: &Node<Statement>) -> 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)

View File

@ -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};

View File

@ -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<AbstractSyntaxTree, DustError> {
/// }
/// }
///
/// assert_eq!(
/// 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),
/// )
/// ]),
/// );
/// 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)),

View File

@ -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),

View File

@ -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<Statement>) -> Result<Option<Value>, 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<Statement>,
identifier: Node<Identifier>,
},
UndefinedProperty {
value: Value,