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
|
|
|
};
|
|
|
|
|
2024-03-17 11:31:45 +00:00
|
|
|
use super::{AbstractTree, 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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 21:14:47 +00:00
|
|
|
impl AbstractTree 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
|
|
|
}
|
|
|
|
|
2024-03-10 18:48:53 +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 {
|
2024-03-10 18:48:53 +00:00
|
|
|
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-10 18:48:53 +00:00
|
|
|
|
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-10 18:48:53 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
2024-03-17 20:59:52 +00:00
|
|
|
let value = self.if_expression.node.run(_context)?.as_return_value()?;
|
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 {
|
|
|
|
self.if_block.run(_context)
|
|
|
|
} else if let Some(else_statement) = self.else_block {
|
|
|
|
else_statement.run(_context)
|
|
|
|
} 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 {
|
|
|
|
actual: value.r#type(),
|
|
|
|
position: self.if_expression.position,
|
|
|
|
},
|
|
|
|
))
|
2024-03-08 19:01:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate::{
|
2024-03-16 19:01:45 +00:00
|
|
|
abstract_tree::{Statement, ValueNode},
|
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
|
|
|
|
)
|
|
|
|
.run(&Context::new()),
|
2024-03-08 21:22:24 +00:00
|
|
|
Ok(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
|
|
|
)
|
|
|
|
.run(&Context::new()),
|
2024-03-08 21:22:24 +00:00
|
|
|
Ok(Action::Return(Value::string("bar".to_string())))
|
2024-03-08 19:01:05 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|