dust/src/abstract_tree/if_else.rs

97 lines
2.5 KiB
Rust
Raw Normal View History

2024-03-08 19:01:05 +00:00
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Expression, Statement, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct IfElse<'src> {
if_expression: Expression<'src>,
if_statement: Box<Statement<'src>>,
else_statement: Option<Box<Statement<'src>>>,
}
impl<'src> IfElse<'src> {
pub fn new(
if_expression: Expression<'src>,
if_statement: Statement<'src>,
else_statement: Option<Statement<'src>>,
) -> Self {
Self {
if_expression,
if_statement: Box::new(if_statement),
else_statement: else_statement.map(|statement| Box::new(statement)),
}
}
}
impl<'src> AbstractTree for IfElse<'src> {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
2024-03-08 19:29:53 +00:00
Ok(Type::None)
2024-03-08 19:01:05 +00:00
}
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
2024-03-08 19:29:53 +00:00
if let Type::Boolean = self.if_expression.expected_type(_context)? {
Ok(())
} else {
Err(ValidationError::ExpectedBoolean)
}
2024-03-08 19:01:05 +00:00
}
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let if_boolean = self
.if_expression
.run(_context)?
.as_return_value()?
.as_boolean()?;
if if_boolean {
self.if_statement.run(_context)
} else if let Some(else_statement) = self.else_statement {
else_statement.run(_context)
} else {
Ok(Action::None)
}
}
}
#[cfg(test)]
mod tests {
use crate::{
abstract_tree::{Action, ValueNode},
context::Context,
Value,
};
use super::*;
#[test]
fn simple_if() {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo"))),
None
)
.run(&Context::new()),
Ok(Action::Return(Value::string("foo")))
)
}
#[test]
fn simple_if_else() {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(false)),
Statement::Expression(Expression::Value(ValueNode::String("foo"))),
Some(Statement::Expression(Expression::Value(ValueNode::String(
"bar"
))))
)
.run(&Context::new()),
Ok(Action::Return(Value::string("bar")))
)
}
}