use crate::ast::binary_expression::BinaryExpression; 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::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::class_symbol::ClassSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use crate::types_table::TypesTable; use std::cell::RefCell; use std::rc::Rc; pub enum Expression { Binary(BinaryExpression), Negative(NegativeExpression), Call(Call), Identifier(Identifier), Integer(IntegerLiteral), Double(DoubleLiteral), String(StringLiteral), } impl Expression { pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) { match self { Expression::Binary(binary_expression) => { binary_expression.init_scopes(symbol_table, container_scope); } Expression::Negative(negative_expression) => { negative_expression.init_scopes(symbol_table, container_scope); } Expression::Call(call) => { call.init_scopes(symbol_table, container_scope); } Expression::Identifier(identifier) => { identifier.init_scope_id(container_scope); } _ => {} } } pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, class_symbol: &ClassSymbol, ) -> Vec { match self { Expression::Binary(binary_expression) => { binary_expression.check_field_initializer_names(symbol_table, class_symbol) } Expression::Negative(negative_expression) => { negative_expression.check_field_initializer_names(symbol_table, class_symbol) } Expression::Call(call) => { call.check_field_initializer_names(symbol_table, class_symbol) } Expression::Identifier(identifier) => { if let Some(diagnostic) = identifier.check_name_as_field_initializer(symbol_table, class_symbol) { vec![diagnostic] } else { vec![] } } _ => vec![], } } pub fn check_constructor_destination_names( &self, symbol_table: &SymbolTable, class_symbol: &ClassSymbol, ) -> Vec { match self { Expression::Binary(_) => { panic!() } Expression::Negative(_) => { panic!() } Expression::Call(_) => { panic!() } Expression::Identifier(identifier) => { if let Some(diagnostic) = identifier.check_constructor_destination_name(symbol_table, class_symbol) { vec![diagnostic] } else { vec![] } } _ => vec![], } } pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, class_symbol: &ClassSymbol, ) -> Vec { match self { Expression::Binary(binary_expression) => { binary_expression.check_constructor_local_names(symbol_table, class_symbol) } Expression::Negative(negative_expression) => { negative_expression.check_constructor_local_names(symbol_table, class_symbol) } Expression::Call(call) => { call.check_constructor_local_names(symbol_table, class_symbol) } Expression::Identifier(identifier) => { if let Some(diagnostic) = identifier.check_constructor_local_name(symbol_table, class_symbol) { vec![diagnostic] } else { vec![] } } _ => vec![], } } pub fn check_method_local_names( &self, symbol_table: &SymbolTable, class_symbol: &ClassSymbol, ) -> Vec { match self { Expression::Binary(binary_expression) => { binary_expression.check_method_local_names(symbol_table, class_symbol) } Expression::Negative(negative_expression) => { negative_expression.check_method_local_names(symbol_table, class_symbol) } Expression::Call(call) => call.check_method_local_names(symbol_table, class_symbol), Expression::Identifier(identifier) => { if let Some(diagnostic) = identifier.check_method_local_name(symbol_table, class_symbol) { vec![diagnostic] } else { vec![] } } _ => vec![], } } pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec { match self { Expression::Binary(binary_expression) => { binary_expression.check_static_fn_local_names(symbol_table) } Expression::Negative(negative_expression) => { negative_expression.check_static_fn_local_names(symbol_table) } Expression::Call(call) => call.check_static_fn_local_names(symbol_table), Expression::Identifier(identifier) => { if let Some(diagnostic) = identifier.check_static_fn_local_name(symbol_table) { vec![diagnostic] } else { vec![] } } Expression::Integer(_) => { vec![] } Expression::Double(_) => { vec![] } Expression::String(_) => { vec![] } } } pub fn type_check( &mut self, symbol_table: &SymbolTable, types_table: &TypesTable, ) -> Result<(), Vec> { match self { Expression::Binary(binary_expression) => { binary_expression.type_check(symbol_table, types_table) } Expression::Negative(negative_expression) => { negative_expression.type_check(symbol_table, types_table) } Expression::Call(call) => call.type_check(symbol_table, types_table), Expression::Identifier(_) => Ok(()), Expression::Integer(_) => Ok(()), Expression::Double(_) => Ok(()), Expression::String(_) => Ok(()), } } pub fn type_info<'a>( &'a self, symbol_table: &SymbolTable, types_table: &'a TypesTable, ) -> &'a TypeInfo { match self { Expression::Binary(binary_expression) => binary_expression.type_info(), Expression::Negative(negative_expression) => negative_expression.type_info(), Expression::Call(call) => call.return_type_info(symbol_table, types_table), Expression::Identifier(identifier) => identifier.type_info(symbol_table, types_table), 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::Binary(binary_expression) => binary_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_operation( &self, builder: &mut IrBuilder, symbol_table: &SymbolTable, types_table: &TypesTable, ) -> IrOperation { match self { Expression::Binary(binary_expression) => { binary_expression.to_ir_operation(builder, symbol_table, types_table) } Expression::Call(call) => { IrOperation::Call(call.to_ir(builder, symbol_table, types_table)) } Expression::Integer(integer_literal) => { IrOperation::Load(IrExpression::Int(integer_literal.value())) } Expression::Double(double_literal) => { IrOperation::Load(IrExpression::Double(double_literal.value())) } Expression::String(string_literal) => { IrOperation::Load(IrExpression::String(string_literal.content().into())) } Expression::Identifier(identifier) => { IrOperation::Load(identifier.ir_expression(builder, symbol_table, types_table)) } Expression::Negative(negative_expression) => { IrOperation::Load(negative_expression.to_ir(builder, symbol_table, types_table)) } } } pub fn to_ir_expression( &self, builder: &mut IrBuilder, symbol_table: &SymbolTable, types_table: &TypesTable, ) -> Option { match self { Expression::Binary(binary_expression) => { Some(binary_expression.to_ir_expression(builder, symbol_table, types_table)) } Expression::Negative(negative_expression) => { Some(negative_expression.to_ir(builder, symbol_table, types_table)) } Expression::Call(call) => { let ir_call = call.to_ir(builder, symbol_table, types_table); if matches!( call.return_type_info(symbol_table, types_table), 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(symbol_table, types_table), ); 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::Identifier(identifier) => { Some(identifier.ir_expression(builder, symbol_table, types_table)) } 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())) } } } }