use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; use crate::diagnostic::Diagnostic; use crate::ir::ir_add::IrAdd; use crate::source_range::SourceRange; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; pub struct AddExpression { lhs: Box, rhs: Box, source_range: SourceRange, type_info: Option, } impl AddExpression { pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self { Self { lhs: lhs.into(), rhs: rhs.into(), source_range, type_info: None, } } pub fn lhs(&self) -> &Expression { &self.lhs } pub fn rhs(&self) -> &Expression { &self.rhs } pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { let diagnostics: Vec = [self.lhs.as_mut(), self.rhs.as_mut()] .iter_mut() .map(|expression| expression.gather_declared_names(symbol_table)) .filter_map(Result::err) .flatten() .collect(); if diagnostics.is_empty() { Ok(()) } else { Err(diagnostics) } } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { let diagnostics: Vec = [self.lhs.as_mut(), self.rhs.as_mut()] .iter_mut() .map(|expression| expression.check_name_usages(symbol_table)) .filter_map(Result::err) .flatten() .collect(); if diagnostics.is_empty() { Ok(()) } else { Err(diagnostics) } } pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { self.lhs.type_check(symbol_table)?; self.rhs.type_check(symbol_table)?; let lhs_type_info = self.lhs.type_info(); let rhs_type_info = self.rhs.type_info(); if lhs_type_info.can_add(rhs_type_info) { self.type_info = Some(lhs_type_info.add_result(rhs_type_info)); Ok(()) } else { Err(vec![Diagnostic::new( &format!("Cannot add {} to {}", lhs_type_info, rhs_type_info), self.source_range.start(), self.source_range.end(), )]) } } pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrAdd { let lhs_ir_expression = self .lhs .to_ir(builder, symbol_table) .expect("Attempt to add non-expression"); let rhs_ir_expression = self .rhs .to_ir(builder, symbol_table) .expect("Attempt to add non-expression"); IrAdd::new(lhs_ir_expression, rhs_ir_expression) } pub fn type_info(&self) -> &TypeInfo { self.type_info.as_ref().unwrap() } pub fn source_range(&self) -> &SourceRange { &self.source_range } }