1
0
dust/dust-lang/src/abstract_tree/if_else.rs

141 lines
4.2 KiB
Rust
Raw Normal View History

2024-03-08 19:01:05 +00:00
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
2024-03-17 20:59:52 +00:00
value::ValueInner,
2024-03-08 19:01:05 +00:00
};
use super::{AbstractNode, Action, Block, Expression, Type, WithPosition};
2024-03-08 19:01:05 +00:00
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
2024-03-08 21:14:47 +00:00
pub struct IfElse {
2024-03-17 11:31:45 +00:00
if_expression: WithPosition<Expression>,
2024-03-17 14:19:22 +00:00
if_block: Block,
else_block: Option<Block>,
2024-03-08 19:01:05 +00:00
}
2024-03-08 21:14:47 +00:00
impl IfElse {
2024-03-17 04:49:01 +00:00
pub fn new(
2024-03-17 11:31:45 +00:00
if_expression: WithPosition<Expression>,
2024-03-17 14:19:22 +00:00
if_block: Block,
else_block: Option<Block>,
2024-03-17 04:49:01 +00:00
) -> Self {
2024-03-08 19:01:05 +00:00
Self {
if_expression,
2024-03-09 20:17:19 +00:00
if_block,
else_block,
2024-03-08 19:01:05 +00:00
}
}
}
impl AbstractNode for IfElse {
2024-03-08 19:01:05 +00:00
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
2024-03-17 14:19:22 +00:00
self.if_block.expected_type(_context)
2024-03-08 19:01:05 +00:00
}
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
2024-03-17 17:36:31 +00:00
self.if_expression.node.validate(context)?;
self.if_block.validate(context)?;
2024-03-17 20:59:52 +00:00
let if_expression_type = self.if_expression.node.expected_type(context)?;
if let Type::Boolean = if_expression_type {
if let Some(else_block) = &self.else_block {
2024-03-17 17:36:31 +00:00
else_block.validate(context)?;
2024-03-17 14:19:22 +00:00
let expected = self.if_block.expected_type(context)?;
let actual = else_block.expected_type(context)?;
2024-03-17 04:49:01 +00:00
expected
.check(&actual)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
2024-03-17 14:19:22 +00:00
actual_position: self.if_block.last_statement().position,
2024-03-17 04:49:01 +00:00
expected_position: self.if_expression.position,
})?;
}
2024-03-08 19:29:53 +00:00
Ok(())
} else {
2024-03-17 20:59:52 +00:00
Err(ValidationError::ExpectedBoolean {
actual: if_expression_type,
position: self.if_expression.position,
})
2024-03-08 19:29:53 +00:00
}
2024-03-08 19:01:05 +00:00
}
2024-03-19 22:31:52 +00:00
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
let action = self.if_expression.node.run(context)?;
2024-03-18 09:39:09 +00:00
let value = if let Action::Return(value) = action {
value
} else {
return Err(RuntimeError::ValidationFailure(
ValidationError::InterpreterExpectedReturn(self.if_expression.position),
));
};
2024-03-08 19:01:05 +00:00
2024-03-17 20:59:52 +00:00
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
if *if_boolean {
2024-03-19 22:31:52 +00:00
self.if_block.run(context)
2024-03-17 20:59:52 +00:00
} else if let Some(else_statement) = self.else_block {
2024-03-19 22:31:52 +00:00
else_statement.run(context)
2024-03-17 20:59:52 +00:00
} else {
Ok(Action::None)
}
2024-03-08 19:01:05 +00:00
} else {
2024-03-17 20:59:52 +00:00
Err(RuntimeError::ValidationFailure(
ValidationError::ExpectedBoolean {
2024-03-19 22:31:52 +00:00
actual: value.r#type(context)?,
2024-03-17 20:59:52 +00:00
position: self.if_expression.position,
},
))
2024-03-08 19:01:05 +00:00
}
}
}
#[cfg(test)]
mod tests {
use crate::{
2024-03-24 16:21:08 +00:00
abstract_tree::{Statement, ValueNode, WithPos},
2024-03-08 19:01:05 +00:00
Value,
};
use super::*;
#[test]
fn simple_if() {
assert_eq!(
IfElse::new(
2024-03-17 11:48:06 +00:00
Expression::Value(ValueNode::Boolean(true)).with_position((0, 0)),
2024-03-17 11:31:45 +00:00
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
))
2024-03-17 14:19:22 +00:00
.with_position((0, 0))]),
2024-03-08 19:01:05 +00:00
None
)
2024-03-17 21:39:39 +00:00
.run(&Context::new())
.unwrap(),
Action::Return(Value::string("foo".to_string()))
2024-03-08 19:01:05 +00:00
)
}
#[test]
fn simple_if_else() {
assert_eq!(
IfElse::new(
2024-03-17 11:48:06 +00:00
Expression::Value(ValueNode::Boolean(false)).with_position((0, 0)),
2024-03-17 11:31:45 +00:00
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
))
2024-03-17 14:19:22 +00:00
.with_position((0, 0))]),
Some(Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("bar".to_string())
))
.with_position((0, 0))]))
2024-03-08 19:01:05 +00:00
)
2024-03-17 21:39:39 +00:00
.run(&Context::new())
.unwrap(),
Action::Return(Value::string("bar".to_string()))
2024-03-08 19:01:05 +00:00
)
}
}