Refactoring top-level constructs.
This commit is contained in:
parent
86fcbb494b
commit
42a5b994d2
@ -11,14 +11,13 @@ use crate::ir::ir_class::{IrClass, IrField};
|
|||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::maybe_return_diagnostics;
|
use crate::maybe_return_diagnostics;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
||||||
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::process::id;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
@ -342,10 +341,8 @@ impl Class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for function in &self.functions {
|
for function in &self.functions {
|
||||||
ir_functions.push(function.to_ir(
|
ir_functions
|
||||||
symbol_table,
|
.push(function.to_ir(symbol_table, Some(self.class_symbol.as_ref().unwrap())));
|
||||||
Some(self.class_symbol.as_ref().unwrap().clone()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_symbol = self.class_symbol.as_ref().unwrap().borrow();
|
let class_symbol = self.class_symbol.as_ref().unwrap().borrow();
|
||||||
|
|||||||
@ -2,7 +2,9 @@ use crate::ast::class::Class;
|
|||||||
use crate::ast::extern_function::ExternFunction;
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
|
use crate::ast::helpers::iter_phase;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::diagnostics_result;
|
||||||
use crate::ir::ir_class::IrClass;
|
use crate::ir::ir_class::IrClass;
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
@ -47,96 +49,75 @@ impl CompilationUnit {
|
|||||||
let mut fqn_context = FqnContext::new(); // in the future, we'll push the pkg/ns on here
|
let mut fqn_context = FqnContext::new(); // in the future, we'll push the pkg/ns on here
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
self.functions
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.functions,
|
||||||
.map(|f| f.gather_declared_names(symbol_table, &fqn_context, None))
|
|f| f.gather_declared_names(symbol_table, &fqn_context, None),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
self.extern_functions
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.extern_functions,
|
||||||
.map(|f| f.gather_declared_names(symbol_table, &fqn_context))
|
|ef| ef.gather_declared_names(symbol_table, &fqn_context),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
self.classes
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.classes,
|
||||||
.map(|c| c.gather_declared_names(symbol_table, &mut fqn_context))
|
|c| c.gather_declared_names(symbol_table, &mut fqn_context),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
diagnostics_result!(diagnostics)
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
self.functions
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.functions,
|
||||||
.map(|f| f.check_name_usages(symbol_table, None))
|
|f| f.check_name_usages(symbol_table, None),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
self.extern_functions
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.extern_functions,
|
||||||
.map(|f| f.check_name_usages(symbol_table, None))
|
|ef| ef.check_name_usages(symbol_table, None),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
self.classes
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.classes,
|
||||||
.map(|c| c.check_name_usages(symbol_table))
|
|c| c.check_name_usages(symbol_table),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
diagnostics_result!(diagnostics)
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
self.functions
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.functions,
|
||||||
.map(|f| f.type_check(symbol_table))
|
|f| f.type_check(symbol_table),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
self.extern_functions
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.extern_functions,
|
||||||
.map(|f| f.type_check(symbol_table))
|
|ef| ef.type_check(symbol_table),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
self.classes
|
iter_phase(
|
||||||
.iter_mut()
|
&mut self.classes,
|
||||||
.map(|c| c.type_check(symbol_table))
|
|c| c.type_check(symbol_table),
|
||||||
.filter_map(Result::err)
|
&mut diagnostics,
|
||||||
.flatten()
|
);
|
||||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
diagnostics_result!(diagnostics)
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, symbol_table: &SymbolTable) -> (Vec<IrClass>, Vec<IrFunction>) {
|
pub fn to_ir(&self, symbol_table: &SymbolTable) -> (Vec<IrClass>, Vec<IrFunction>) {
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
|
use crate::ast::helpers::{gather_oks, iter_phase, map_symbol_insert_result};
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics, ok_or_return};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -37,13 +39,12 @@ impl ExternFunction {
|
|||||||
&self.declared_name
|
&self.declared_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
/// Inserts and saves a `FunctionSymbol`.
|
||||||
|
fn insert_save_function_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
fqn_context: &FqnContext,
|
fqn_context: &FqnContext,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
|
||||||
|
|
||||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||||
&self.declared_name,
|
&self.declared_name,
|
||||||
self.declared_name_source_range.clone(),
|
self.declared_name_source_range.clone(),
|
||||||
@ -51,61 +52,108 @@ impl ExternFunction {
|
|||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
|
|
||||||
let function_symbol = match insert_result {
|
let function_symbol = ok_or_return!(map_symbol_insert_result(
|
||||||
Ok(function_symbol) => function_symbol,
|
insert_result,
|
||||||
Err(symbol_insert_error) => {
|
&self.declared_name_source_range
|
||||||
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)
|
|
||||||
|
self.function_symbol = Some(function_symbol);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
/// Gathers parameters' declared names, and sets `ParameterSymbols` on the `FunctionSymbol`.
|
||||||
|
fn gather_parameters_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
|
let parameter_symbols = gather_oks(
|
||||||
|
&mut self.parameters,
|
||||||
|
|p| p.gather_declared_names(symbol_table),
|
||||||
|
&mut diagnostics,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Only continue if we have all the parameters and no diagnostics.
|
||||||
|
maybe_return_diagnostics!(diagnostics);
|
||||||
|
|
||||||
|
self.function_symbol
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.set_parameters(parameter_symbols);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
/// Gathers return type names
|
||||||
|
fn gather_return_type_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
handle_diagnostics!(
|
||||||
|
self.return_type.gather_declared_names(symbol_table),
|
||||||
|
diagnostics
|
||||||
|
);
|
||||||
|
diagnostics_result!(diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &FqnContext,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.insert_save_function_symbol(symbol_table, fqn_context)?;
|
||||||
|
|
||||||
symbol_table
|
symbol_table
|
||||||
.push_function_scope(&format!("extern_function_scope({})", &self.declared_name));
|
.push_function_scope(&format!("extern_function_scope({})", &self.declared_name));
|
||||||
|
|
||||||
let mut parameter_symbols = vec![];
|
self.gather_parameters_names(symbol_table)
|
||||||
for parameter in &mut self.parameters {
|
.inspect_err(|_| symbol_table.pop_scope())?; // pop scope if we had diagnostics!
|
||||||
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
|
// handle return type
|
||||||
match self.return_type.gather_declared_names(symbol_table) {
|
self.gather_return_type_names(symbol_table)
|
||||||
Ok(_) => {}
|
.inspect_err(|_| symbol_table.pop_scope())?;
|
||||||
Err(mut type_use_diagnostics) => {
|
|
||||||
diagnostics.append(&mut type_use_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol_table.pop_scope(); // function scope
|
symbol_table.pop_scope(); // function scope
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_parameters_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
iter_phase(
|
||||||
|
&mut self.parameters,
|
||||||
|
|p| p.check_name_usages(symbol_table, class_context),
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_return_type_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
handle_diagnostics!(
|
||||||
|
self.return_type
|
||||||
|
.check_name_usages(symbol_table, class_context),
|
||||||
|
diagnostics
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `FunctionSymbol`'s return type info.
|
||||||
|
fn set_function_symbol_return_type(&mut self) {
|
||||||
|
self.function_symbol
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.set_return_type_info(self.return_type.type_info().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
pub fn check_name_usages(
|
||||||
@ -113,50 +161,46 @@ impl ExternFunction {
|
|||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = self
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
.parameters
|
|
||||||
.iter_mut()
|
|
||||||
.map(|parameter| parameter.check_name_usages(symbol_table, class_context))
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
match self
|
self.check_parameters_names(symbol_table, class_context, &mut diagnostics);
|
||||||
.return_type
|
|
||||||
.check_name_usages(symbol_table, class_context)
|
self.check_return_type_names(symbol_table, class_context, &mut diagnostics);
|
||||||
{
|
|
||||||
Ok(_) => {}
|
maybe_return_diagnostics!(diagnostics);
|
||||||
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
|
// set return type info on symbol now that its available
|
||||||
self.function_symbol
|
self.set_function_symbol_return_type();
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_return_type_info(self.return_type.type_info().clone());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_check_parameters(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
iter_phase(
|
||||||
|
&mut self.parameters,
|
||||||
|
|p| p.type_check(symbol_table),
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_check_return_type(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
handle_diagnostics!(self.return_type.type_check(symbol_table), diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let diagnostics: Vec<Diagnostic> = self
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
.parameters
|
|
||||||
.iter_mut()
|
self.type_check_parameters(symbol_table, &mut diagnostics);
|
||||||
.map(|parameter| parameter.type_check(symbol_table))
|
self.type_check_return_type(symbol_table, &mut diagnostics);
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
diagnostics_result!(diagnostics)
|
||||||
.collect();
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::ast::fqn_util::fqn_parts_to_string;
|
use crate::ast::fqn_util::fqn_parts_to_string;
|
||||||
|
use crate::ast::helpers::{
|
||||||
|
gather_oks, iter_phase, iter_phase_enumerated, map_symbol_insert_result,
|
||||||
|
};
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::handle_diagnostics;
|
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||||
@ -13,8 +15,9 @@ use crate::source_range::SourceRange;
|
|||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics, ok_or_return};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -57,54 +60,8 @@ impl Function {
|
|||||||
self.statements.iter().collect()
|
self.statements.iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
/// Inserts a "self" parameter at index 0.
|
||||||
&mut self,
|
fn insert_self_parameter(&mut self) {
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics = vec![];
|
|
||||||
|
|
||||||
if !diagnostics.is_empty() {
|
|
||||||
return Err(diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert function symbol
|
|
||||||
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()),
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
|
|
||||||
// get function symbol if successful
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// save function symbol for later
|
|
||||||
self.function_symbol = Some(function_symbol.clone());
|
|
||||||
|
|
||||||
// handle parameters
|
|
||||||
symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name));
|
|
||||||
|
|
||||||
// first, if we are in a class context, insert a "fake" self parameter
|
|
||||||
if let Some(class_symbol) = class_context {
|
|
||||||
self.parameters.insert(
|
self.parameters.insert(
|
||||||
0,
|
0,
|
||||||
Parameter::new(
|
Parameter::new(
|
||||||
@ -115,72 +72,147 @@ impl Function {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `class_context` is `Some`, calls `insert_self_parameter()`.
|
||||||
|
fn maybe_insert_self_parameter(&mut self, class_context: Option<&Rc<RefCell<ClassSymbol>>>) {
|
||||||
|
if class_context.is_some() {
|
||||||
|
self.insert_self_parameter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts and saves to self a `FunctionSymbol`
|
||||||
|
fn insert_save_function_symbol(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &FqnContext,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
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()),
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
|
// get function symbol if successful
|
||||||
|
let function_symbol = ok_or_return!(map_symbol_insert_result(
|
||||||
|
insert_result,
|
||||||
|
&self.declared_name_source_range
|
||||||
|
));
|
||||||
|
|
||||||
|
// save function symbol for later
|
||||||
|
self.function_symbol = Some(function_symbol.clone());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gathers all declared names in parameters
|
||||||
|
fn gather_parameters_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
// handle self case
|
||||||
|
self.maybe_insert_self_parameter(class_context);
|
||||||
|
|
||||||
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
// now gather all names for the params
|
// now gather all names for the params
|
||||||
let mut parameter_symbols = vec![];
|
let parameter_symbols = gather_oks(
|
||||||
for parameter in &mut self.parameters {
|
&mut self.parameters,
|
||||||
match parameter.gather_declared_names(symbol_table) {
|
|p| p.gather_declared_names(symbol_table),
|
||||||
Ok(parameter_symbol) => {
|
&mut diagnostics,
|
||||||
parameter_symbols.push(parameter_symbol);
|
);
|
||||||
}
|
|
||||||
Err(mut parameter_diagnostics) => {
|
// important: if there were diagnostics we don't have all the param symbols
|
||||||
diagnostics.append(&mut parameter_diagnostics);
|
// n.b.: passing pop_scope callback because we don't want to mess up the scopes for others
|
||||||
}
|
maybe_return_diagnostics!(diagnostics);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set params on function symbol
|
// set params on function symbol
|
||||||
function_symbol
|
self.function_symbol
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_parameters(parameter_symbols);
|
.set_parameters(parameter_symbols);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gathers all return type names
|
||||||
|
fn gather_return_type_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
iter_phase(
|
||||||
|
self.return_type.as_mut_slice(),
|
||||||
|
|type_use| type_use.gather_declared_names(symbol_table),
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gathers all statements' names
|
||||||
|
fn gather_statements_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
iter_phase(
|
||||||
|
&mut self.statements,
|
||||||
|
|s| s.gather_declared_names(symbol_table),
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &FqnContext,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
// function symbol
|
||||||
|
self.insert_save_function_symbol(symbol_table, fqn_context)?;
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name));
|
||||||
|
self.gather_parameters_names(symbol_table, class_context)
|
||||||
|
.inspect_err(|_| symbol_table.pop_scope())?; // if we errored, we need to fix scopes
|
||||||
|
|
||||||
// return type
|
// return type
|
||||||
if let Some(type_use) = &mut self.return_type {
|
let mut diagnostics = vec![];
|
||||||
match type_use.gather_declared_names(symbol_table) {
|
self.gather_return_type_names(symbol_table, &mut diagnostics);
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut type_use_diagnostics) => {
|
|
||||||
diagnostics.append(&mut type_use_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// enter main block
|
||||||
symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name));
|
symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name));
|
||||||
for statement in &mut self.statements {
|
|
||||||
match statement.gather_declared_names(symbol_table) {
|
// statements
|
||||||
Ok(_) => {}
|
self.gather_statements_names(symbol_table, &mut diagnostics);
|
||||||
Err(mut statement_diagnostics) => {
|
|
||||||
diagnostics.append(&mut statement_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
symbol_table.pop_scope(); // main block scope
|
symbol_table.pop_scope(); // main block scope
|
||||||
symbol_table.pop_scope(); // function scope
|
symbol_table.pop_scope(); // function scope
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
diagnostics_result!(diagnostics)
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
/// Checks parameter name usages
|
||||||
|
fn check_parameter_names(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
let mut diagnostics = vec![];
|
) {
|
||||||
|
iter_phase(
|
||||||
// parameters
|
&mut self.parameters,
|
||||||
diagnostics.append(
|
|p| p.check_name_usages(symbol_table, class_context),
|
||||||
&mut self
|
diagnostics,
|
||||||
.parameters
|
|
||||||
.iter_mut()
|
|
||||||
.map(|parameter| parameter.check_name_usages(symbol_table, class_context))
|
|
||||||
.filter_map(|result| result.err())
|
|
||||||
.flatten()
|
|
||||||
.collect(),
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// return type
|
/// Checks return type name usages, if there is a `TypeUse` present. If `None`, sets the
|
||||||
|
/// `FunctionSymbol`'s return type to `TypeInfo::Void`.
|
||||||
|
fn check_return_type_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
if let Some(type_use) = &mut self.return_type {
|
if let Some(type_use) = &mut self.return_type {
|
||||||
match type_use.check_name_usages(symbol_table, class_context) {
|
match type_use.check_name_usages(symbol_table, class_context) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@ -203,81 +235,111 @@ impl Function {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_return_type_info(TypeInfo::Void);
|
.set_return_type_info(TypeInfo::Void);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks all statement name usages.
|
||||||
|
fn check_statement_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
iter_phase(
|
||||||
|
&mut self.statements,
|
||||||
|
|s| s.check_name_usages(symbol_table),
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_name_usages(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
self.check_parameter_names(symbol_table, class_context, &mut diagnostics);
|
||||||
|
|
||||||
|
// return type
|
||||||
|
self.check_return_type_names(symbol_table, class_context, &mut diagnostics);
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
for statement in &mut self.statements {
|
self.check_statement_names(symbol_table, &mut diagnostics);
|
||||||
match statement.check_name_usages(symbol_table) {
|
|
||||||
Ok(_) => {}
|
diagnostics_result!(diagnostics)
|
||||||
Err(mut statement_diagnostics) => {
|
|
||||||
diagnostics.append(&mut statement_diagnostics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the return type `TypeInfo`. This function is only safe to call after an `Ok` call to
|
||||||
|
/// `check_return_type_names()`.
|
||||||
|
fn get_return_type_info(&self) -> TypeInfo {
|
||||||
|
let function_symbol = self.function_symbol.as_ref().unwrap().borrow();
|
||||||
|
function_symbol.return_type_info().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type checks parameters.
|
||||||
|
fn type_check_parameters(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
iter_phase(
|
||||||
|
&mut self.parameters,
|
||||||
|
|p| p.type_check(symbol_table),
|
||||||
|
diagnostics,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type checks return type.
|
||||||
|
fn type_check_return_type(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
if let Some(type_use) = &mut self.return_type {
|
||||||
|
handle_diagnostics!(type_use.type_check(symbol_table), diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
/// Type checks statements, making sure the last statement matches return type, if necessary.
|
||||||
Ok(())
|
fn type_check_statements(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
let return_type_info = self.get_return_type_info();
|
||||||
|
let statements_len = self.statements.len();
|
||||||
|
|
||||||
|
iter_phase_enumerated(
|
||||||
|
&mut self.statements,
|
||||||
|
|i, s| {
|
||||||
|
let is_last = i == statements_len - 1;
|
||||||
|
if is_last {
|
||||||
|
s.type_check(symbol_table, Some(&return_type_info))
|
||||||
} else {
|
} else {
|
||||||
Err(diagnostics)
|
s.type_check(symbol_table, None)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
diagnostics.append(
|
self.type_check_parameters(symbol_table, &mut diagnostics);
|
||||||
&mut self
|
|
||||||
.parameters
|
|
||||||
.iter_mut()
|
|
||||||
.map(|parameter| parameter.type_check(symbol_table))
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let function_symbol = self.function_symbol.as_ref().unwrap();
|
|
||||||
let return_type_info = function_symbol.borrow().return_type_info().clone();
|
|
||||||
let statements_len = self.statements.len();
|
|
||||||
|
|
||||||
// return type
|
// return type
|
||||||
if let Some(type_use) = &mut self.return_type {
|
self.type_check_return_type(symbol_table, &mut diagnostics);
|
||||||
handle_diagnostics!(type_use.type_check(symbol_table), diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
diagnostics.append(
|
self.type_check_statements(symbol_table, &mut diagnostics);
|
||||||
&mut self
|
|
||||||
.statements
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, statement)| {
|
|
||||||
let is_last = i == statements_len - 1;
|
|
||||||
if is_last {
|
|
||||||
statement.type_check(symbol_table, Some(&return_type_info))
|
|
||||||
} else {
|
|
||||||
statement.type_check(symbol_table, None)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
diagnostics_result!(diagnostics)
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(
|
/// Converts all parameters to ir. Saves the IrParameter to the associated parameter symbol.
|
||||||
&self,
|
fn parameters_to_ir(&self, builder: &mut IrBuilder) {
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> IrFunction {
|
|
||||||
let mut builder = IrBuilder::new();
|
|
||||||
|
|
||||||
// parameters
|
|
||||||
for (i, parameter) in self.parameters.iter().enumerate() {
|
for (i, parameter) in self.parameters.iter().enumerate() {
|
||||||
let parameter_symbol = parameter.parameter_symbol();
|
let parameter_symbol = parameter.parameter_symbol();
|
||||||
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
|
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
|
||||||
@ -290,33 +352,57 @@ impl Function {
|
|||||||
builder.parameters_mut().push(as_rc.clone());
|
builder.parameters_mut().push(as_rc.clone());
|
||||||
parameter_symbol.borrow_mut().set_ir_parameter(as_rc);
|
parameter_symbol.borrow_mut().set_ir_parameter(as_rc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let entry_block_id = builder.new_block();
|
/// If `class_context.is_some()`, set parameter 0 to the self parameter/variable on the builder.
|
||||||
|
fn handle_method_case(
|
||||||
// preamble
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
) {
|
||||||
// if we are a method, we need to set the self parameter on the builder
|
// if we are a method, we need to set the self parameter on the builder
|
||||||
if let Some(_) = class_context {
|
if class_context.is_some() {
|
||||||
let parameter_0 = builder.parameters()[0].clone();
|
let parameter_0 = builder.parameters()[0].clone();
|
||||||
// put it in the self parameter
|
// put it in the self parameter
|
||||||
builder.set_self_parameter_or_variable(IrParameterOrVariable::IrParameter(parameter_0));
|
builder.set_self_parameter_or_variable(IrParameterOrVariable::IrParameter(parameter_0));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let function_symbol = self.function_symbol.as_ref().unwrap().borrow();
|
/// Convert all statements to ir.
|
||||||
let return_type_info = function_symbol.return_type_info();
|
fn statements_to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
||||||
|
let return_type_info = self.get_return_type_info();
|
||||||
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
|
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
|
||||||
|
|
||||||
for (i, statement) in self.statements.iter().enumerate() {
|
for (i, statement) in self.statements.iter().enumerate() {
|
||||||
let is_last = i == self.statements.len() - 1;
|
let is_last = i == self.statements.len() - 1;
|
||||||
statement.to_ir(&mut builder, symbol_table, should_return_value && is_last);
|
statement.to_ir(builder, symbol_table, should_return_value && is_last);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ir(
|
||||||
|
&self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
|
) -> IrFunction {
|
||||||
|
let mut builder = IrBuilder::new();
|
||||||
|
|
||||||
|
// parameters
|
||||||
|
self.parameters_to_ir(&mut builder);
|
||||||
|
|
||||||
|
let entry_block_id = builder.new_block();
|
||||||
|
|
||||||
|
// preamble
|
||||||
|
self.handle_method_case(&mut builder, class_context);
|
||||||
|
|
||||||
|
// body
|
||||||
|
self.statements_to_ir(&mut builder, symbol_table);
|
||||||
|
|
||||||
builder.finish_block();
|
builder.finish_block();
|
||||||
|
|
||||||
let entry_block = builder.get_block(entry_block_id).clone();
|
let entry_block = builder.get_block(entry_block_id).clone();
|
||||||
IrFunction::new(
|
IrFunction::new(
|
||||||
fqn_parts_to_string(self.function_symbol.as_ref().unwrap().borrow().fqn_parts()),
|
fqn_parts_to_string(self.function_symbol.as_ref().unwrap().borrow().fqn_parts()),
|
||||||
builder.parameters(),
|
builder.parameters(),
|
||||||
return_type_info,
|
&self.get_return_type_info(),
|
||||||
entry_block,
|
entry_block,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
79
dmc-lib/src/ast/helpers.rs
Normal file
79
dmc-lib/src/ast/helpers.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
||||||
|
use crate::error_codes::SYMBOL_ALREADY_DECLARED;
|
||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::symbol_table::SymbolInsertError;
|
||||||
|
|
||||||
|
/// Iterates through all `ts`, running the `phase` function, and pushing returned `Diagnostic`s
|
||||||
|
/// into `diagnostics`.
|
||||||
|
pub fn iter_phase<T>(
|
||||||
|
ts: &mut [T],
|
||||||
|
mut phase: impl FnMut(&mut T) -> Result<(), Vec<Diagnostic>>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
ts.iter_mut()
|
||||||
|
.map(|t| phase(t))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.for_each(|d| diagnostics.push(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `iter_phase` but enumerated.
|
||||||
|
pub fn iter_phase_enumerated<T>(
|
||||||
|
ts: &mut [T],
|
||||||
|
mut phase: impl FnMut(usize, &mut T) -> Result<(), Vec<Diagnostic>>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) {
|
||||||
|
ts.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, t)| phase(i, t))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.for_each(|d| diagnostics.push(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_symbol_insert_result<T>(
|
||||||
|
insert_result: Result<T, SymbolInsertError>,
|
||||||
|
declared_name_source_range: &SourceRange,
|
||||||
|
) -> Result<T, Vec<Diagnostic>> {
|
||||||
|
match insert_result {
|
||||||
|
Ok(symbol) => Ok(symbol),
|
||||||
|
Err(symbol_insert_error) => match symbol_insert_error {
|
||||||
|
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||||
|
let already_declared_symbol = already_declared.symbol().borrow();
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
&format!(
|
||||||
|
"Symbol {} already declared in current scope.",
|
||||||
|
already_declared_symbol.declared_name()
|
||||||
|
),
|
||||||
|
declared_name_source_range.start(),
|
||||||
|
declared_name_source_range.end(),
|
||||||
|
)
|
||||||
|
.with_reporter(file!(), line!())
|
||||||
|
.with_error_code(SYMBOL_ALREADY_DECLARED)
|
||||||
|
.with_secondary_labels(&[SecondaryLabel::new(
|
||||||
|
already_declared_symbol.declared_name_source_range().start(),
|
||||||
|
already_declared_symbol.declared_name_source_range().end(),
|
||||||
|
Some("Symbol already declared here.".to_string()),
|
||||||
|
)]);
|
||||||
|
Err(vec![diagnostic])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_oks<T, R>(
|
||||||
|
ts: &mut [T],
|
||||||
|
mut f: impl FnMut(&mut T) -> Result<R, Vec<Diagnostic>>,
|
||||||
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
) -> Vec<R> {
|
||||||
|
let mut rs: Vec<R> = vec![];
|
||||||
|
for t in &mut ts[..] {
|
||||||
|
match f(t) {
|
||||||
|
Ok(r) => rs.push(r),
|
||||||
|
Err(mut t_diagnostics) => {
|
||||||
|
diagnostics.append(&mut t_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rs
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ pub mod fqn_context;
|
|||||||
pub mod fqn_util;
|
pub mod fqn_util;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod generic_parameter;
|
pub mod generic_parameter;
|
||||||
|
mod helpers;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod integer_literal;
|
pub mod integer_literal;
|
||||||
pub mod ir_builder;
|
pub mod ir_builder;
|
||||||
|
|||||||
@ -22,6 +22,27 @@ macro_rules! handle_diagnostics {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ok_or_return {
|
||||||
|
( $result: expr, $diagnostics: expr ) => {
|
||||||
|
match $result {
|
||||||
|
Ok(inner) => inner,
|
||||||
|
Err(mut diagnostics) => {
|
||||||
|
$diagnostics.append(&mut diagnostics);
|
||||||
|
return Err($diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $result: expr ) => {
|
||||||
|
match $result {
|
||||||
|
Ok(inner) => inner,
|
||||||
|
Err(diagnostics) => {
|
||||||
|
return Err(diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! maybe_return_diagnostics {
|
macro_rules! maybe_return_diagnostics {
|
||||||
( $diagnostics: expr ) => {
|
( $diagnostics: expr ) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user