deimos-lang/dmc-lib/src/ast/extern_function.rs
2026-03-20 20:39:30 -05:00

135 lines
4.2 KiB
Rust

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<str>,
declared_name_source_range: SourceRange,
parameters: Vec<Parameter>,
return_type: TypeUse,
scope_id: Option<usize>,
}
impl ExternFunction {
pub fn new(
name: &str,
declared_name_source_range: SourceRange,
parameters: Vec<Parameter>,
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<FunctionSymbol>, Vec<Symbol>) {
let mut all_symbols: Vec<Symbol> = 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<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = 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<Diagnostic>,
) {
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<Diagnostic>,
) {
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<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = 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)
}
}