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, symbol_types: &str, diagnostics: &mut Vec, ) { 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, ) { // 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, ) { 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); } } } }