/*! # Name Analysis There are two phases in name analysis. ## 1. Gather The gather phase has three responsibilities: 1. Add all declared symbols to the symbol table. 2. Set the `scope_id` property of all identifiers and fully-qualified-names. 3. For the main identifiers of `UseStatement`s (i.e., the last identifier in the `UseStatement`): set a 'linking' symbol on the identifier, which will later be filled in with the linked-to symbol (probably in another file, or from the standard library). ## 2. Resolve The resolve phase has one main responsibility: resolve all references based on the identifier's `scope_id` property. */ // use crate::name_analysis::resolve::resolve_compilation_unit; use crate::ast::ast_node::AstNode; use crate::ast::node::CompilationUnit; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::gather::gather_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; use codespan_reporting::files::Files; use std::collections::HashMap; use std::hash::Hash; use crate::name_analysis::scope_table::ScopeTable; pub(self) mod fqn_context; mod gather; // mod resolve; pub mod symbol; pub mod symbol_table; mod scope_table; pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( compilation_units: &[Box], files: &'a F, symbol_table: &mut SymbolTable, ) -> Vec { let mut diagnostics = vec![]; let mut scope_table = ScopeTable::new(); // gather symbols for compilation_unit in compilation_units { let file_name = files.name(compilation_unit.file_id()).unwrap(); gather_compilation_unit( compilation_unit, &file_name, symbol_table, &mut scope_table, &mut diagnostics, ); } // resolve symbols for compilation_unit in compilation_units { // resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); } diagnostics.into() } // #[cfg(test)] // mod tests { // use super::*; // use crate::ast::build::build_ast; // use crate::ast::children::NodeRef; // use crate::ast::walk::walk_depth_first; // use crate::parser::{DeimosParser, Rule}; // use crate::std_core::add_std_core_symbols; // use codespan_reporting::files::SimpleFiles; // use codespan_reporting::term; // use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; // use indoc::indoc; // use pest::Parser; // use std::collections::HashMap; // // fn assert_number_of_diagnostics( // sources: HashMap<&str, &str>, // symbol_table: &mut SymbolTable, // n_diagnostics: usize, // ) -> Vec { // let mut files = SimpleFiles::new(); // let mut compilation_units = vec![]; // // for (file_name, source) in sources { // let file_id = files.add(file_name, source); // let parse_result = DeimosParser::parse(Rule::CompilationUnit, source); // if let Err(err) = &parse_result { // panic!("{}", err); // } // let mut pairs = parse_result.unwrap(); // if pairs.as_str().trim() != source.trim() { // panic!("Parsing did not consume entire input."); // } // // compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap())); // } // // let diagnostics = analyze_names(&mut compilation_units, symbol_table); // // if diagnostics.len() != n_diagnostics { // let writer = StandardStream::stderr(ColorChoice::Always); // let config = term::Config::default(); // // for diagnostic in &diagnostics { // term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap(); // } // // eprintln!("{}", symbol_table); // } // // assert_eq!(n_diagnostics, diagnostics.len()); // // compilation_units // } // // fn assert_no_diagnostics( // sources: HashMap<&str, &str>, // symbol_table: &mut SymbolTable, // ) -> Vec { // assert_number_of_diagnostics(sources, symbol_table, 0) // } // // fn assert_saved_symbols(compilation_unit: &CompilationUnit) { // walk_depth_first(compilation_unit, &mut |node_ref| match node_ref { // NodeRef::Identifier(identifier) => { // if identifier.saved_symbol().is_none() { // panic!("{:?} does not have a saved symbol.", identifier) // } // } // NodeRef::FullyQualifiedName(fqn) => { // if fqn.saved_symbol().is_none() { // panic!("{:?} does not have a saved symbol.", fqn) // } // } // NodeRef::UseStatement(use_statement) => match use_statement { // _ => todo!(), // }, // _ => {} // }) // } // // fn assert_resolved_symbols(compilation_unit: &CompilationUnit) { // walk_depth_first(compilation_unit, &mut |node_ref| match node_ref { // NodeRef::UseStatement(use_statement) => match use_statement { // _ => todo!(), // }, // _ => {} // }) // } // // #[test] // fn params_seen() { // let sources: HashMap<&str, &str> = HashMap::from([( // "main.dm", // indoc! {" // fn main(args: Array) { // let x = args; // }"}, // )]); // // let cus = assert_no_diagnostics(sources, &mut SymbolTable::new()); // for ref cu in cus { // assert_saved_symbols(cu); // } // } // // #[test] // fn two_files() { // let sources: HashMap<&str, &str> = HashMap::from([ // ( // "main.dm", // indoc! {" // use test::Greeter; // "}, // ), // ( // "deps.dm", // indoc! {" // ns test; // // pub class Greeter {} // "}, // ), // ]); // // let cus = assert_no_diagnostics(sources, &mut SymbolTable::new()); // for ref cu in cus { // assert_saved_symbols(cu); // assert_resolved_symbols(cu); // } // } // // #[test] // fn sees_std_core_println() { // let sources: HashMap<&str, &str> = HashMap::from([( // "main.dm", // indoc! {" // fn main(args: Array) { // println(args) // } // "}, // )]); // // let mut symbol_table = SymbolTable::new(); // add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols."); // let cus = assert_no_diagnostics(sources, &mut symbol_table); // for ref cu in cus { // assert_saved_symbols(cu); // assert_resolved_symbols(cu); // } // } // // #[test] // fn sees_duplicate_fn() { // let sources: HashMap<&str, &str> = HashMap::from([( // "main.dm", // indoc! {" // fn main(args: Array) {} // fn main(args: Array) {} // "}, // )]); // assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1); // } // // #[test] // fn use_class_from_other_file() { // let sources: HashMap<&str, &str> = HashMap::from([ // ( // "main.dm", // indoc! {" // use greeter::Greeter; // // fn test(greeter: Greeter) {} // "}, // ), // ( // "greeter.dm", // indoc! {" // ns greeter; // // class Greeter {} // "}, // ), // ]); // let mut symbol_table = SymbolTable::new(); // let cus = assert_no_diagnostics(sources, &mut symbol_table); // for ref cu in cus { // assert_saved_symbols(cu); // assert_resolved_symbols(cu); // } // } // // #[test] // fn shadow_import() { // let sources: HashMap<&str, &str> = HashMap::from([ // ( // "main.dm", // indoc! {" // use greeter::Greeter; // // class Greeter {} // "}, // ), // ( // "greeter.dm", // indoc! {" // ns greeter; // // class Greeter {} // "}, // ), // ]); // assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1); // } // }