deimos-lang/dmc-lib/src/ast/extern_function.rs
2026-03-13 17:19:25 -05:00

163 lines
5.0 KiB
Rust

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