use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; use crate::diagnostic::Diagnostic; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_multiply::IrMultiply; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use std::cell::RefCell; use std::rc::Rc; pub struct NegativeExpression { operand: Box, source_range: SourceRange, type_info: Option, } impl NegativeExpression { pub fn new(operand: Expression, source_range: SourceRange) -> Self { Self { operand: operand.into(), source_range, type_info: None, } } pub fn source_range(&self) -> &SourceRange { &self.source_range } pub fn operand(&self) -> &Expression { &self.operand } pub fn operand_mut(&mut self) -> &mut Expression { &mut self.operand } pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { self.operand.gather_declared_names(symbol_table) } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { self.operand.check_name_usages(symbol_table) } pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { self.operand.type_check(symbol_table)?; let type_info = self.operand.type_info(); if type_info.can_negate() { self.type_info = Some(type_info.negate_result()); Ok(()) } else { Err(vec![Diagnostic::new( &format!("Cannot negate {}", type_info), self.source_range.start(), self.source_range.end(), )]) } } pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrExpression { let operand_as_ir = self .operand .to_ir_expression(builder, symbol_table) .expect("Attempt to negate non-value expression"); match operand_as_ir { IrExpression::Parameter(parameter) => { let destination = Rc::new(RefCell::new(IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), parameter.type_info(), ))); let rhs = match parameter.type_info() { TypeInfo::Integer => IrExpression::Int(-1), TypeInfo::Double => IrExpression::Double(-1.0), _ => panic!("Trying to multiply with a non-integer/double"), }; let operation = IrOperation::Multiply(IrMultiply::new(IrExpression::Parameter(parameter), rhs)); let assign = IrAssign::new(destination.clone(), operation); builder .current_block_mut() .add_statement(IrStatement::Assign(assign)); IrExpression::Variable(destination) } IrExpression::Variable(variable) => { let destination = Rc::new(RefCell::new(IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), variable.borrow().type_info(), ))); let rhs = match variable.borrow().type_info() { TypeInfo::Integer => IrExpression::Int(-1), TypeInfo::Double => IrExpression::Double(-1.0), _ => panic!("Trying to multiply with a non-integer/double"), }; let operation = IrOperation::Multiply(IrMultiply::new(IrExpression::Variable(variable), rhs)); let assign = IrAssign::new(destination.clone(), operation); builder .current_block_mut() .add_statement(IrStatement::Assign(assign)); IrExpression::Variable(destination) } IrExpression::Int(i) => IrExpression::Int(i * -1), IrExpression::Double(d) => IrExpression::Double(d * -1.0), IrExpression::String(_) => { panic!("Attempt to negate IrExpression::String") } } } pub fn type_info(&self) -> &TypeInfo { self.type_info.as_ref().unwrap() } }