use crate::ast::fqn_context::FqnContext; use crate::ast::helpers::{collect_diagnostics_into_mut, collect_parameter_symbols_into}; use crate::ast::parameter::Parameter; use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::Symbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics}; use std::rc::Rc; pub struct ExternFunction { declared_name: Rc, declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, scope_id: Option, } impl ExternFunction { pub fn new( name: &str, declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, ) -> Self { Self { declared_name: name.into(), declared_name_source_range, parameters, return_type, scope_id: None, } } pub fn declared_name(&self) -> &str { &self.declared_name } pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) { self.scope_id = Some(container_scope); symbol_table.push_function_scope(&format!("extern_function_scope({})", self.declared_name)); for parameter in &mut self.parameters { parameter.init_scopes(symbol_table, container_scope); } self.return_type.init_scopes(symbol_table, container_scope); symbol_table.pop_scope(); } pub fn make_symbols(&self, fqn_context: &FqnContext) -> (Rc, Vec) { let mut all_symbols: Vec = Vec::new(); let mut parameter_symbols = Vec::new(); collect_parameter_symbols_into(&self.parameters, &mut all_symbols, &mut parameter_symbols); let function_symbol = Rc::new(FunctionSymbol::new( &self.declared_name, self.declared_name_source_range.clone(), fqn_context.resolve(self.declared_name()), true, false, self.scope_id.unwrap(), parameter_symbols, )); all_symbols.push(Symbol::Function(function_symbol.clone())); (function_symbol, all_symbols) } pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); for parameter in &self.parameters { diagnostics.append(&mut parameter.check_names(symbol_table)); } diagnostics.append(&mut self.return_type.check_names(symbol_table)); diagnostics } pub fn gather_types(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) { let function_symbol = symbol_table .get_function_symbol_owned(self.scope_id.unwrap(), self.declared_name()) .unwrap(); let resolved_return_type = self .return_type .type_info(symbol_table, types_table) .clone(); types_table .function_return_types_mut() .insert(function_symbol, resolved_return_type); } fn type_check_parameters( &mut self, symbol_table: &SymbolTable, types_table: &TypesTable, diagnostics: &mut Vec, ) { collect_diagnostics_into_mut( &mut self.parameters, |p| p.type_check(symbol_table, types_table), diagnostics, ); } fn type_check_return_type( &mut self, symbol_table: &SymbolTable, types_table: &TypesTable, diagnostics: &mut Vec, ) { handle_diagnostics!( self.return_type.type_check(symbol_table, types_table), diagnostics ); } pub fn type_check( &mut self, symbol_table: &SymbolTable, types_table: &TypesTable, ) -> Result<(), Vec> { let mut diagnostics: Vec = vec![]; self.type_check_parameters(symbol_table, types_table, &mut diagnostics); self.type_check_return_type(symbol_table, types_table, &mut diagnostics); diagnostics_result!(diagnostics) } }