dust/src/abstract_tree/assignment.rs

103 lines
2.5 KiB
Rust
Raw Normal View History

use crate::{
error::{RuntimeError, ValidationError},
Context,
};
2024-02-25 18:49:26 +00:00
2024-03-08 17:24:11 +00:00
use super::{AbstractTree, Action, Identifier, Statement, Type};
2024-02-25 18:49:26 +00:00
2024-02-25 19:26:22 +00:00
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
2024-02-26 21:27:01 +00:00
pub struct Assignment<'src> {
identifier: Identifier,
r#type: Option<Type>,
2024-02-26 21:27:01 +00:00
statement: Box<Statement<'src>>,
2024-02-25 18:49:26 +00:00
}
2024-02-26 21:27:01 +00:00
impl<'src> Assignment<'src> {
pub fn new(identifier: Identifier, r#type: Option<Type>, statement: Statement<'src>) -> Self {
2024-02-25 18:49:26 +00:00
Self {
identifier,
r#type,
2024-02-25 18:49:26 +00:00
statement: Box::new(statement),
}
}
}
2024-02-26 21:27:01 +00:00
impl<'src> AbstractTree for Assignment<'src> {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
todo!()
}
2024-03-06 17:15:03 +00:00
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
2024-03-06 23:15:25 +00:00
let statement_type = self.statement.expected_type(context)?;
2024-03-06 17:15:03 +00:00
2024-03-06 23:15:25 +00:00
if let Some(expected) = &self.r#type {
2024-03-06 17:15:03 +00:00
expected.check(&statement_type)?;
2024-03-06 23:15:25 +00:00
context.set_type(self.identifier.clone(), expected.clone())?;
} else {
context.set_type(self.identifier.clone(), statement_type)?;
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> {
let action = self.statement.run(context)?;
let value = match action {
Action::Return(value) => value,
r#break => return Ok(r#break),
};
2024-02-25 18:49:26 +00:00
2024-03-06 23:15:25 +00:00
context.set_value(self.identifier, value)?;
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},
error::TypeCheckError,
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(
Identifier::new("foobar"),
None,
Statement::Expression(Expression::Value(ValueNode::Integer(42))),
)
.run(&context)
.unwrap();
2024-02-26 21:27:01 +00:00
2024-03-02 00:15:03 +00:00
assert_eq!(
2024-03-06 23:15:25 +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 type_check() {
let validation = Assignment::new(
Identifier::new("foobar"),
Some(Type::Boolean),
Statement::Expression(Expression::Value(ValueNode::Integer(42))),
)
.validate(&Context::new());
assert_eq!(
validation,
Err(ValidationError::TypeCheck(TypeCheckError {
actual: Type::Integer,
expected: Type::Boolean
}))
)
}
2024-02-25 18:49:26 +00:00
}