use crate::ast::add_expression::AddExpression; use crate::ast::call::Call; use crate::ast::double_literal::DoubleLiteral; use crate::ast::identifier::Identifier; use crate::ast::integer_literal::IntegerLiteral; use crate::ast::ir_builder::IrBuilder; use crate::ast::negative_expression::NegativeExpression; use crate::ast::string_literal::StringLiteral; use crate::ast::subtract_expression::SubtractExpression; use crate::diagnostic::Diagnostic; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; 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 enum Expression { Add(AddExpression), Subtract(SubtractExpression), Negative(NegativeExpression), Call(Call), Identifier(Identifier), Integer(IntegerLiteral), Double(DoubleLiteral), String(StringLiteral), } impl Expression { pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { match self { Expression::Add(add_expression) => add_expression.gather_declared_names(symbol_table), Expression::Subtract(subtract_expression) => { subtract_expression.gather_declared_names(symbol_table) } Expression::Negative(negative_expression) => { negative_expression.gather_declared_names(symbol_table) } Expression::Call(call) => call.gather_declared_names(symbol_table), Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table), Expression::Integer(_) => Ok(()), Expression::Double(_) => Ok(()), Expression::String(_) => Ok(()), } } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { match self { Expression::Add(add_expression) => add_expression.check_name_usages(symbol_table), Expression::Subtract(subtract_expression) => { subtract_expression.check_name_usages(symbol_table) } Expression::Negative(negative_expression) => { negative_expression.check_name_usages(symbol_table) } Expression::Call(call) => call.check_name_usages(symbol_table), Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table), Expression::Integer(_) => Ok(()), Expression::Double(_) => Ok(()), Expression::String(_) => Ok(()), } } pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { match self { Expression::Add(add_expression) => add_expression.type_check(symbol_table), Expression::Subtract(subtract_expression) => { subtract_expression.type_check(symbol_table) } Expression::Negative(negative_expression) => { negative_expression.type_check(symbol_table) } Expression::Call(call) => call.type_check(symbol_table), Expression::Identifier(identifier) => identifier.type_check(symbol_table), Expression::Integer(_) => Ok(()), Expression::Double(_) => Ok(()), Expression::String(_) => Ok(()), } } pub fn type_info(&self) -> &TypeInfo { match self { Expression::Add(add_expression) => add_expression.type_info(), Expression::Subtract(subtract_expression) => subtract_expression.type_info(), Expression::Negative(negative_expression) => negative_expression.type_info(), Expression::Call(call) => call.return_type_info(), Expression::Identifier(identifier) => identifier.type_info(), Expression::Integer(integer_literal) => integer_literal.type_info(), Expression::Double(double_literal) => double_literal.type_info(), Expression::String(string_literal) => string_literal.type_info(), } } pub fn source_range(&self) -> &SourceRange { match self { Expression::Add(additive_expression) => additive_expression.source_range(), Expression::Subtract(subtract_expression) => subtract_expression.source_range(), Expression::Negative(negative_expression) => negative_expression.source_range(), Expression::Call(call) => call.source_range(), Expression::Identifier(identifier) => identifier.source_range(), Expression::Integer(integer_literal) => integer_literal.source_range(), Expression::Double(double_literal) => double_literal.source_range(), Expression::String(string_literal) => string_literal.source_range(), } } pub fn to_ir( &self, builder: &mut IrBuilder, symbol_table: &SymbolTable, ) -> Option { match self { Expression::Call(call) => { let ir_call = call.to_ir(builder, symbol_table); if matches!(call.return_type_info(), TypeInfo::Void) { builder .current_block_mut() .add_statement(IrStatement::Call(ir_call)); None } else { let t_var = IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), call.return_type_info(), ); let as_rc = Rc::new(RefCell::new(t_var)); let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call)); builder .current_block_mut() .add_statement(IrStatement::Assign(assign)); Some(IrExpression::Variable(as_rc)) } } Expression::Integer(integer_literal) => { Some(IrExpression::Int(integer_literal.value())) } Expression::Double(double_literal) => { Some(IrExpression::Double(double_literal.value())) } Expression::String(string_literal) => { Some(IrExpression::String(string_literal.content().into())) } Expression::Identifier(identifier) => { let expressible_symbol = identifier.expressible_symbol(); Some(expressible_symbol.ir_expression(builder)) } Expression::Add(additive_expression) => { let ir_add = additive_expression.to_ir(builder, symbol_table); let t_var = IrVariable::new_vr( builder.new_t_var().into(), builder.current_block().id(), additive_expression.type_info(), ); let as_rc = Rc::new(RefCell::new(t_var)); let assign = IrAssign::new(as_rc.clone(), IrOperation::Add(ir_add)); builder .current_block_mut() .add_statement(IrStatement::Assign(assign)); Some(IrExpression::Variable(as_rc)) } Expression::Subtract(subtract_expression) => { Some(subtract_expression.to_ir_expression(builder, symbol_table)) } Expression::Negative(negative_expression) => { Some(negative_expression.to_ir(builder, symbol_table)) } } } }