2024-06-26 16:50:46 +00:00
|
|
|
use std::fmt::{self, Display, Formatter};
|
|
|
|
|
2024-06-04 18:47:15 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
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-06-22 00:59:38 +00:00
|
|
|
use super::{AbstractNode, Block, Evaluation, Expression, Type, WithPosition};
|
2024-03-08 19:01:05 +00:00
|
|
|
|
2024-06-04 18:47:15 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
2024-03-08 21:14:47 +00:00
|
|
|
pub struct IfElse {
|
2024-06-17 14:10:06 +00:00
|
|
|
if_expression: Expression,
|
2024-03-25 05:36:33 +00:00
|
|
|
if_block: WithPosition<Block>,
|
2024-06-20 23:25:46 +00:00
|
|
|
else_ifs: Option<Vec<(Expression, WithPosition<Block>)>>,
|
2024-03-25 05:36:33 +00:00
|
|
|
else_block: Option<WithPosition<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-06-17 14:10:06 +00:00
|
|
|
if_expression: Expression,
|
2024-03-25 05:36:33 +00:00
|
|
|
if_block: WithPosition<Block>,
|
2024-06-20 23:25:46 +00:00
|
|
|
else_ifs: Option<Vec<(Expression, WithPosition<Block>)>>,
|
2024-03-25 05:36:33 +00:00
|
|
|
else_block: Option<WithPosition<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,
|
2024-03-25 04:16:55 +00:00
|
|
|
else_ifs,
|
2024-03-09 20:17:19 +00:00
|
|
|
else_block,
|
2024-03-08 19:01:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-22 00:59:38 +00:00
|
|
|
impl AbstractNode for IfElse {
|
2024-07-02 17:11:31 +00:00
|
|
|
fn define_and_validate(
|
|
|
|
&self,
|
|
|
|
context: &Context,
|
|
|
|
manage_memory: bool,
|
|
|
|
) -> Result<(), ValidationError> {
|
|
|
|
self.if_expression
|
|
|
|
.define_and_validate(context, manage_memory)?;
|
|
|
|
self.if_block
|
|
|
|
.node
|
|
|
|
.define_and_validate(context, manage_memory)?;
|
2024-03-17 17:36:31 +00:00
|
|
|
|
2024-06-22 03:37:25 +00:00
|
|
|
let if_expression_type = if let Some(r#type) = self.if_expression.expected_type(context)? {
|
|
|
|
r#type
|
|
|
|
} else {
|
2024-07-01 20:59:39 +00:00
|
|
|
return Err(ValidationError::ExpectedValueStatement(
|
2024-06-22 03:37:25 +00:00
|
|
|
self.if_expression.position(),
|
|
|
|
));
|
|
|
|
};
|
2024-06-24 06:18:58 +00:00
|
|
|
let if_block_type = self.if_block.node.expected_type(context)?;
|
2024-03-25 05:56:06 +00:00
|
|
|
|
2024-06-20 23:25:46 +00:00
|
|
|
if let Some(else_ifs) = &self.else_ifs {
|
|
|
|
for (expression, block) in else_ifs {
|
|
|
|
let expression_type = expression.expected_type(context)?;
|
2024-03-25 05:56:06 +00:00
|
|
|
|
2024-06-22 03:37:25 +00:00
|
|
|
if let Some(Type::Boolean) = expression_type {
|
2024-07-02 17:11:31 +00:00
|
|
|
block.node.define_and_validate(context, manage_memory)?;
|
2024-03-25 05:56:06 +00:00
|
|
|
|
2024-06-24 06:18:58 +00:00
|
|
|
let else_if_block_type = block.node.expected_type(context)?;
|
|
|
|
|
|
|
|
if let (Some(expected), Some(actual)) = (&if_block_type, else_if_block_type) {
|
|
|
|
expected
|
|
|
|
.check(&actual)
|
|
|
|
.map_err(|conflict| ValidationError::TypeCheck {
|
|
|
|
conflict,
|
|
|
|
actual_position: self.if_block.node.last_statement().position(),
|
|
|
|
expected_position: Some(self.if_expression.position()),
|
|
|
|
})?;
|
|
|
|
}
|
2024-06-20 23:25:46 +00:00
|
|
|
} else {
|
|
|
|
return Err(ValidationError::ExpectedBoolean {
|
|
|
|
actual: if_expression_type,
|
|
|
|
position: self.if_expression.position(),
|
|
|
|
});
|
|
|
|
}
|
2024-03-25 05:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-24 06:18:58 +00:00
|
|
|
if let Some(block) = &self.else_block {
|
2024-07-02 17:11:31 +00:00
|
|
|
block.node.define_and_validate(context, manage_memory)?;
|
2024-06-24 06:18:58 +00:00
|
|
|
|
|
|
|
let else_if_block_type = block.node.expected_type(context)?;
|
|
|
|
|
|
|
|
if let (Some(expected), Some(actual)) = (if_block_type, else_if_block_type) {
|
|
|
|
expected
|
|
|
|
.check(&actual)
|
|
|
|
.map_err(|conflict| ValidationError::TypeCheck {
|
|
|
|
conflict,
|
|
|
|
actual_position: self.if_block.node.last_statement().position(),
|
|
|
|
expected_position: Some(self.if_expression.position()),
|
|
|
|
})?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-25 05:56:06 +00:00
|
|
|
Ok(())
|
2024-03-08 19:01:05 +00:00
|
|
|
}
|
|
|
|
|
2024-06-22 00:59:38 +00:00
|
|
|
fn evaluate(
|
2024-06-17 14:10:06 +00:00
|
|
|
self,
|
2024-06-22 00:59:38 +00:00
|
|
|
context: &Context,
|
2024-06-17 14:10:06 +00:00
|
|
|
_manage_memory: bool,
|
2024-06-21 22:28:12 +00:00
|
|
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
2024-03-25 04:16:55 +00:00
|
|
|
let if_position = self.if_expression.position();
|
2024-06-22 03:37:25 +00:00
|
|
|
let evaluation = self.if_expression.evaluate(context, _manage_memory)?;
|
|
|
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
2024-03-18 09:39:09 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(RuntimeError::ValidationFailure(
|
2024-07-01 20:59:39 +00:00
|
|
|
ValidationError::ExpectedValueStatement(if_position),
|
2024-03-18 09:39:09 +00:00
|
|
|
));
|
|
|
|
};
|
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-06-22 03:37:25 +00:00
|
|
|
return self.if_block.node.evaluate(context, _manage_memory);
|
2024-06-20 23:25:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(else_ifs) = self.else_ifs {
|
|
|
|
for (expression, block) in else_ifs {
|
2024-03-25 05:56:06 +00:00
|
|
|
let expression_position = expression.position();
|
2024-06-22 03:37:25 +00:00
|
|
|
let evaluation = expression.evaluate(context, _manage_memory)?;
|
|
|
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
2024-03-25 05:56:06 +00:00
|
|
|
value
|
|
|
|
} else {
|
|
|
|
return Err(RuntimeError::ValidationFailure(
|
2024-07-01 20:59:39 +00:00
|
|
|
ValidationError::ExpectedValueStatement(expression_position),
|
2024-03-25 05:56:06 +00:00
|
|
|
));
|
|
|
|
};
|
|
|
|
|
|
|
|
if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
|
|
|
|
if *else_if_boolean {
|
2024-06-22 03:37:25 +00:00
|
|
|
return block.node.evaluate(context, _manage_memory);
|
2024-03-25 05:56:06 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(RuntimeError::ValidationFailure(
|
|
|
|
ValidationError::ExpectedBoolean {
|
|
|
|
actual: value.r#type(context)?,
|
|
|
|
position: expression_position,
|
|
|
|
},
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
2024-06-20 23:25:46 +00:00
|
|
|
}
|
2024-03-25 05:56:06 +00:00
|
|
|
|
2024-06-20 23:25:46 +00:00
|
|
|
if let Some(else_statement) = self.else_block {
|
2024-06-22 03:37:25 +00:00
|
|
|
else_statement.node.evaluate(context, _manage_memory)
|
2024-06-20 23:25:46 +00:00
|
|
|
} else {
|
2024-06-21 22:28:12 +00:00
|
|
|
Ok(None)
|
2024-03-17 20:59:52 +00:00
|
|
|
}
|
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-25 04:16:55 +00:00
|
|
|
position: if_position,
|
2024-03-17 20:59:52 +00:00
|
|
|
},
|
|
|
|
))
|
2024-03-08 19:01:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-22 00:59:38 +00:00
|
|
|
fn expected_type(&self, _context: &Context) -> Result<Option<Type>, ValidationError> {
|
2024-06-16 07:12:04 +00:00
|
|
|
self.if_block.node.expected_type(_context)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-26 16:50:46 +00:00
|
|
|
impl Display for IfElse {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
let IfElse {
|
|
|
|
if_expression,
|
|
|
|
if_block,
|
|
|
|
else_ifs,
|
|
|
|
else_block,
|
|
|
|
} = self;
|
|
|
|
|
|
|
|
write!(f, "if {if_expression} {}", if_block.node)?;
|
|
|
|
|
|
|
|
if let Some(else_ifs) = else_ifs {
|
|
|
|
for (expression, block) in else_ifs {
|
|
|
|
write!(f, "else if {expression} {}", block.node)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(else_block) = else_block {
|
|
|
|
write!(f, "{}", else_block.node)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-06-17 14:10:06 +00:00
|
|
|
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
2024-06-17 19:47:07 +00:00
|
|
|
Block::new(vec![Statement::Expression(Expression::Value(
|
2024-03-25 04:16:55 +00:00
|
|
|
ValueNode::String("foo".to_string()).with_position((0, 0))
|
2024-03-25 05:36:33 +00:00
|
|
|
))])
|
|
|
|
.with_position((0, 0)),
|
2024-06-20 23:25:46 +00:00
|
|
|
Some(Vec::with_capacity(0)),
|
2024-03-08 19:01:05 +00:00
|
|
|
None
|
|
|
|
)
|
2024-06-22 03:37:25 +00:00
|
|
|
.evaluate(&Context::new(None), true)
|
2024-03-17 21:39:39 +00:00
|
|
|
.unwrap(),
|
2024-06-21 22:28:12 +00:00
|
|
|
Some(Evaluation::Return(Value::string("foo".to_string())))
|
2024-03-08 19:01:05 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|