use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; use crate::diagnostic::Diagnostic; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::source_range::SourceRange; use crate::symbol::{ExpressibleSymbol, FunctionSymbol}; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use std::cell::RefCell; use std::rc::Rc; pub struct Call { callee: Box, arguments: Vec, source_range: SourceRange, } impl Call { pub fn new(callee: Expression, arguments: Vec, source_range: SourceRange) -> Self { Self { callee: callee.into(), arguments, source_range, } } pub fn callee(&self) -> &Expression { &self.callee } pub fn arguments(&self) -> Vec<&Expression> { self.arguments.iter().collect() } pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec { let mut diagnostics = vec![]; diagnostics.append(&mut self.callee.gather_declared_names(symbol_table)); for argument in &mut self.arguments { diagnostics.append(&mut argument.gather_declared_names(symbol_table)); } diagnostics } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics = vec![]; diagnostics.append(&mut self.callee.check_name_usages(symbol_table)); for argument in &mut self.arguments { diagnostics.append(&mut argument.check_name_usages(symbol_table)); } diagnostics } pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics = vec![]; diagnostics.append(&mut self.callee.type_check(symbol_table)); for argument in &mut self.arguments { diagnostics.append(&mut argument.type_check(symbol_table)); } // check that callee is callable let function_symbol = match self.callee.type_info() { TypeInfo::Function(function_symbol) => function_symbol, _ => { diagnostics.push(Diagnostic::new( "Receiver is not callable", self.callee.source_range().start(), self.callee.source_range().end(), )); return diagnostics; } }; // check arguments length let function_symbol_ref = function_symbol.borrow(); let parameters = function_symbol_ref.parameters(); if parameters.len() != self.arguments.len() { diagnostics.push(Diagnostic::new( &format!( "Wrong number of arguments; expected {} but found {}", parameters.len(), self.arguments.len() ), self.source_range.start(), self.source_range.end(), )); } if !diagnostics.is_empty() { return diagnostics; } // check argument types for i in 0..parameters.len() { let parameter = ¶meters[i]; let argument = &self.arguments[i]; if !parameter .borrow() .type_info() .is_assignable_from(&argument.type_info()) { diagnostics.push(Diagnostic::new( &format!( "Mismatched types; expected {} but found {}", parameter.borrow().type_info(), argument.type_info() ), argument.source_range().start(), argument.source_range().end(), )) } } diagnostics } pub fn type_info(&self) -> TypeInfo { match self.callee.type_info() { TypeInfo::Function(function_symbol) => function_symbol.borrow().return_type(), _ => panic!(), } } fn get_callee_symbol(&self) -> Rc> { match self.callee() { Expression::Identifier(identifier) => { let expressible_symbol = identifier.expressible_symbol(); match expressible_symbol { ExpressibleSymbol::Function(function_symbol) => function_symbol.clone(), _ => panic!("Calling things other than functions not yet supported."), } } _ => panic!("Calling things other than identifiers not yet supported."), } } pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrCall { let arguments: Vec = self .arguments .iter() .map(|argument| argument.to_ir(builder, symbol_table)) .inspect(|expression| { if expression.is_none() { panic!("Attempt to pass non-expression") } }) .map(Option::unwrap) .collect(); let function_symbol = self.get_callee_symbol(); IrCall::new( function_symbol.borrow().name_owned(), arguments, function_symbol.clone(), ) } pub fn source_range(&self) -> &SourceRange { &self.source_range } }