dust/src/abstract_tree/assignment.rs

217 lines
6.3 KiB
Rust
Raw Normal View History

use crate::{
error::{RuntimeError, ValidationError},
Context,
};
2024-02-25 18:49:26 +00:00
2024-03-17 11:31:45 +00:00
use super::{AbstractTree, Action, Identifier, Statement, Type, WithPosition};
2024-02-25 18:49:26 +00:00
2024-02-25 19:26:22 +00:00
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
2024-03-08 21:14:47 +00:00
pub struct Assignment {
2024-03-18 07:24:41 +00:00
identifier: WithPosition<Identifier>,
2024-03-17 11:31:45 +00:00
r#type: Option<WithPosition<Type>>,
operator: AssignmentOperator,
2024-03-17 11:31:45 +00:00
statement: Box<WithPosition<Statement>>,
2024-02-25 18:49:26 +00:00
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum AssignmentOperator {
Assign,
AddAssign,
SubAssign,
}
2024-03-08 21:14:47 +00:00
impl Assignment {
pub fn new(
2024-03-18 07:24:41 +00:00
identifier: WithPosition<Identifier>,
2024-03-17 11:31:45 +00:00
r#type: Option<WithPosition<Type>>,
operator: AssignmentOperator,
2024-03-17 11:31:45 +00:00
statement: WithPosition<Statement>,
) -> Self {
2024-02-25 18:49:26 +00:00
Self {
identifier,
r#type,
operator,
2024-02-25 18:49:26 +00:00
statement: Box::new(statement),
}
}
}
2024-03-08 21:14:47 +00:00
impl AbstractTree for Assignment {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
2024-03-11 19:17:01 +00:00
Ok(Type::None)
}
2024-03-06 17:15:03 +00:00
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
2024-03-17 04:49:01 +00:00
let statement_type = self.statement.node.expected_type(context)?;
2024-03-17 11:31:45 +00:00
if let Some(WithPosition {
2024-03-17 04:49:01 +00:00
node: expected_type,
position: expected_position,
}) = &self.r#type
{
expected_type.check(&statement_type).map_err(|conflict| {
ValidationError::TypeCheck {
conflict,
actual_position: self.statement.position,
expected_position: expected_position.clone(),
}
})?;
2024-03-06 23:15:25 +00:00
2024-03-18 07:24:41 +00:00
context.set_type(self.identifier.node.clone(), expected_type.clone())?;
2024-03-06 23:15:25 +00:00
} else {
2024-03-18 07:24:41 +00:00
context.set_type(self.identifier.node.clone(), statement_type)?;
2024-03-06 17:15:03 +00:00
}
2024-03-18 07:24:41 +00:00
self.identifier.node.validate(context)?;
2024-03-17 04:49:01 +00:00
self.statement.node.validate(context)?;
2024-03-11 18:49:44 +00:00
2024-03-06 17:15:03 +00:00
Ok(())
}
2024-03-08 17:24:11 +00:00
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
2024-03-17 04:49:01 +00:00
let action = self.statement.node.run(context)?;
2024-03-08 17:24:11 +00:00
let value = match action {
Action::Return(value) => value,
r#break => return Ok(r#break),
};
2024-02-25 18:49:26 +00:00
match self.operator {
AssignmentOperator::Assign => {
2024-03-18 07:24:41 +00:00
context.set_value(self.identifier.node, value)?;
}
AssignmentOperator::AddAssign => {
2024-03-18 07:24:41 +00:00
if let Some(previous_value) = context.get_value(&self.identifier.node)? {
let new_value = previous_value.add(&value)?;
2024-03-18 07:24:41 +00:00
context.set_value(self.identifier.node, new_value)?;
} else {
return Err(RuntimeError::ValidationFailure(
2024-03-18 07:24:41 +00:00
ValidationError::VariableNotFound {
identifier: self.identifier.node,
position: self.identifier.position,
},
));
}
}
AssignmentOperator::SubAssign => {
2024-03-18 07:24:41 +00:00
if let Some(previous_value) = context.get_value(&self.identifier.node)? {
let new_value = previous_value.subtract(&value)?;
2024-03-18 07:24:41 +00:00
context.set_value(self.identifier.node, new_value)?;
} else {
return Err(RuntimeError::ValidationFailure(
2024-03-18 07:24:41 +00:00
ValidationError::VariableNotFound {
identifier: self.identifier.node,
position: self.identifier.position,
},
));
}
}
}
2024-02-25 18:49:26 +00:00
2024-03-08 17:24:11 +00:00
Ok(Action::None)
2024-02-25 18:49:26 +00:00
}
}
#[cfg(test)]
mod tests {
2024-03-06 17:15:03 +00:00
use crate::{
abstract_tree::{Expression, ValueNode},
2024-03-17 04:49:01 +00:00
error::TypeConflict,
2024-03-08 17:24:11 +00:00
Value,
2024-03-06 17:15:03 +00:00
};
2024-03-02 00:15:03 +00:00
use super::*;
2024-02-25 18:49:26 +00:00
#[test]
fn assign_value() {
2024-03-02 00:15:03 +00:00
let context = Context::new();
2024-02-26 21:27:01 +00:00
2024-03-02 00:15:03 +00:00
Assignment::new(
2024-03-18 07:24:41 +00:00
Identifier::new("foobar").with_position((0, 0)),
2024-03-02 00:15:03 +00:00
None,
AssignmentOperator::Assign,
2024-03-17 11:48:06 +00:00
Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)),
2024-03-02 00:15:03 +00:00
)
.run(&context)
.unwrap();
2024-02-26 21:27:01 +00:00
2024-03-02 00:15:03 +00:00
assert_eq!(
2024-03-17 17:36:31 +00:00
context.get_value(&Identifier::new("foobar")),
2024-03-02 00:15:03 +00:00
Ok(Some(Value::integer(42)))
)
2024-02-25 18:49:26 +00:00
}
2024-03-06 17:15:03 +00:00
#[test]
fn add_assign_value() {
let context = Context::new();
context
.set_value(Identifier::new("foobar"), Value::integer(1))
.unwrap();
Assignment::new(
2024-03-18 07:24:41 +00:00
Identifier::new("foobar").with_position((0, 0)),
None,
AssignmentOperator::AddAssign,
2024-03-17 11:48:06 +00:00
Statement::Expression(Expression::Value(ValueNode::Integer(41))).with_position((0, 0)),
)
.run(&context)
.unwrap();
assert_eq!(
2024-03-17 17:36:31 +00:00
context.get_value(&Identifier::new("foobar")),
Ok(Some(Value::integer(42)))
)
}
#[test]
fn subtract_assign_value() {
let context = Context::new();
context
.set_value(Identifier::new("foobar"), Value::integer(43))
.unwrap();
Assignment::new(
2024-03-18 07:24:41 +00:00
Identifier::new("foobar").with_position((0, 0)),
None,
AssignmentOperator::SubAssign,
2024-03-17 11:48:06 +00:00
Statement::Expression(Expression::Value(ValueNode::Integer(1))).with_position((0, 0)),
)
.run(&context)
.unwrap();
assert_eq!(
2024-03-17 17:36:31 +00:00
context.get_value(&Identifier::new("foobar")),
Ok(Some(Value::integer(42)))
)
}
2024-03-06 17:15:03 +00:00
#[test]
fn type_check() {
let validation = Assignment::new(
2024-03-18 07:24:41 +00:00
Identifier::new("foobar").with_position((0, 0)),
2024-03-17 11:31:45 +00:00
Some(WithPosition {
2024-03-17 04:49:01 +00:00
node: Type::Boolean,
2024-03-17 11:48:06 +00:00
position: (0, 0).into(),
2024-03-17 04:49:01 +00:00
}),
AssignmentOperator::Assign,
2024-03-17 11:48:06 +00:00
Statement::Expression(Expression::Value(ValueNode::Integer(42))).with_position((0, 0)),
2024-03-06 17:15:03 +00:00
)
.validate(&Context::new());
assert_eq!(
validation,
2024-03-17 04:49:01 +00:00
Err(ValidationError::TypeCheck {
conflict: TypeConflict {
actual: Type::Integer,
expected: Type::Boolean
},
2024-03-17 11:48:06 +00:00
actual_position: (0, 0).into(),
expected_position: (0, 0).into(),
2024-03-17 04:49:01 +00:00
})
2024-03-06 17:15:03 +00:00
)
}
2024-02-25 18:49:26 +00:00
}