use crate::ast::fqn_context::FqnContext; use crate::ast::parameter::Parameter; use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; use std::cell::RefCell; use std::rc::Rc; pub struct ExternFunction { declared_name: String, declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, function_symbol: Option>>, } impl ExternFunction { pub fn new( name: &str, declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, ) -> ExternFunction { ExternFunction { declared_name: name.into(), declared_name_source_range, parameters, return_type, function_symbol: None, } } pub fn declared_name(&self) -> &str { &self.declared_name } pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, fqn_context: &FqnContext, ) -> Result<(), Vec> { let mut diagnostics = vec![]; let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( &self.declared_name, self.declared_name_source_range.clone(), fqn_context.resolve(self.declared_name()), true, )); let function_symbol = match insert_result { Ok(function_symbol) => function_symbol, Err(symbol_insert_error) => { return match symbol_insert_error { SymbolInsertError::AlreadyDeclared(already_declared) => { diagnostics.push(Diagnostic::new( &format!( "Function {} already declared in current scope.", already_declared.symbol().borrow().declared_name() ), self.declared_name_source_range.start(), self.declared_name_source_range.end(), )); Err(diagnostics) } }; } }; symbol_table .push_function_scope(&format!("extern_function_scope({})", &self.declared_name)); let mut parameter_symbols = vec![]; for parameter in &mut self.parameters { let parameter_result = parameter.gather_declared_names(symbol_table); match parameter_result { Ok(parameter_symbol) => { parameter_symbols.push(parameter_symbol); } Err(mut parameter_diagnostics) => { diagnostics.append(&mut parameter_diagnostics); } } } function_symbol .borrow_mut() .set_parameters(parameter_symbols); self.function_symbol = Some(function_symbol); // handle return type match self.return_type.gather_declared_names(symbol_table) { Ok(_) => {} Err(mut type_use_diagnostics) => { diagnostics.append(&mut type_use_diagnostics); } } symbol_table.pop_scope(); // function scope if diagnostics.is_empty() { Ok(()) } else { Err(diagnostics) } } pub fn check_name_usages( &mut self, symbol_table: &SymbolTable, class_context: Option<&Rc>>, ) -> Result<(), Vec> { let mut diagnostics: Vec = self .parameters .iter_mut() .map(|parameter| parameter.check_name_usages(symbol_table, class_context)) .filter_map(Result::err) .flatten() .collect(); match self .return_type .check_name_usages(symbol_table, class_context) { Ok(_) => {} Err(mut return_type_diagnostics) => { diagnostics.append(&mut return_type_diagnostics); } } if diagnostics.is_empty() { // set return type info on symbol now that its available self.function_symbol .as_mut() .unwrap() .borrow_mut() .set_return_type_info(self.return_type.type_info().clone()); Ok(()) } else { Err(diagnostics) } } pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { let diagnostics: Vec = self .parameters .iter_mut() .map(|parameter| parameter.type_check(symbol_table)) .filter_map(Result::err) .flatten() .collect(); if diagnostics.is_empty() { Ok(()) } else { Err(diagnostics) } } }