use std::sync::Arc; use colored::Colorize; use crate::{ data::{self, tuple::TupleT, Data, Type}, errors::{error_colors, CheckError, SourceRange}, }; use super::MersStatement; #[derive(Debug)] pub struct If { pub pos_in_src: SourceRange, pub condition: Box, pub on_true: Box, pub on_false: Option>, } impl MersStatement for If { fn check_custom( &self, info: &mut super::CheckInfo, init_to: Option<&Type>, ) -> Result { if init_to.is_some() { return Err("can't init to statement type If".to_string().into()); } let cond_return_type = self.condition.check(info, None)?; if !cond_return_type.is_included_in_single(&data::bool::BoolT) { return Err(CheckError::new() .src(vec![ (self.pos_in_src.clone(), None), ( self.condition.source_range(), Some(error_colors::IfConditionNotBool), ), ]) .msg(format!( "The {} in an if-statement must return bool, not {}", "condition".color(error_colors::IfConditionNotBool), cond_return_type .to_string() .color(error_colors::IfConditionNotBool), ))); } let mut t = self.on_true.check(info, None)?; if let Some(f) = &self.on_false { t.add_all(&f.check(info, None)?); } else { t.add(Arc::new(TupleT(vec![]))); } Ok(t) } fn run_custom(&self, info: &mut super::Info) -> crate::data::Data { if let Some(data::bool::Bool(true)) = self .condition .run(info) .get() .as_any() .downcast_ref::() { self.on_true.run(info) } else if let Some(on_false) = &self.on_false { on_false.run(info) } else { Data::empty_tuple() } } fn has_scope(&self) -> bool { true } fn source_range(&self) -> SourceRange { self.pos_in_src.clone() } fn inner_statements(&self) -> Vec<&dyn MersStatement> { if let Some(on_false) = &self.on_false { vec![ self.condition.as_ref(), self.on_true.as_ref(), on_false.as_ref(), ] } else { vec![self.condition.as_ref(), self.on_true.as_ref()] } } fn as_any(&self) -> &dyn std::any::Any { self } }