deimos-lang/src/name_analysis/second_pass.rs

99 lines
3.3 KiB
Rust

use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::use_symbol::UseSymbol;
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
use crate::name_analysis::util::use_statement_base_fqn;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use std::range::Range;
fn handle_lookup_error(
err: SymbolLookupError,
error_symbol_name: &str,
error_file_id: usize,
error_range: Range<usize>,
symbol_types: &str,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match err {
SymbolLookupError::NoDefinition => {
let diagnostic = Diagnostic::error()
.with_message(format!(
"No such {} symbol '{}' in scope.",
symbol_types, error_symbol_name,
))
.with_label(
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
);
diagnostics.push(diagnostic);
}
}
}
pub fn nap2_compilation_unit(
compilation_unit: &mut CompilationUnit,
symbol_table: &SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// TODO: check namespace for proper file name
for use_statement in compilation_unit.use_statements_mut() {
nap2_use_statement(use_statement, symbol_table, diagnostics);
}
// TODO: declarations
}
fn nap2_use_statement(
use_statement: &mut UseStatement,
symbol_table: &SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn = use_statement_base_fqn(use_statement);
let mut handle_concrete_use_symbol = |identifier: &Identifier| {
let fqn = format!("{}::{}", base_fqn, identifier.name());
match symbol_table.resolve_concrete_usable_by_fqn(&fqn) {
Ok(resolved_symbol) => match *use_statement.use_symbol().unwrap().borrow() {
UseSymbol::Concrete(ref concrete_use_symbol) => {
concrete_use_symbol
.borrow_mut()
.set_resolved_symbol(resolved_symbol);
}
_ => panic!("Unexpected symbol type"),
},
Err(lookup_error) => {
handle_lookup_error(
lookup_error,
&fqn,
use_statement.file_id(),
use_statement.range(),
"Usable Symbol",
diagnostics,
);
}
}
};
match use_statement.suffix() {
UseStatementSuffix::Identifier(identifier) => {
handle_concrete_use_symbol(identifier);
}
UseStatementSuffix::Star => {
if let Err(error) = symbol_table.resolve_usable_star(&base_fqn) {
handle_lookup_error(
error,
&base_fqn,
use_statement.file_id(),
use_statement.range(),
"Star Usable Symbol",
diagnostics,
);
}
}
UseStatementSuffix::UseList(use_list) => {
for identifier in use_list.identifiers() {
handle_concrete_use_symbol(identifier);
}
}
}
}