163 lines
5.0 KiB
Rust
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)
|
|
}
|
|
}
|
|
}
|