use crate::ast::named::Named; use crate::ast::CompilationUnit; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::gather::gather_compilation_unit; use crate::name_analysis::resolve::resolve_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; mod fqn_context; mod gather; mod resolve; pub mod symbol; pub mod symbol_table; pub(self) struct DiagnosticsContainer { diagnostics: Vec, } impl DiagnosticsContainer { pub fn new() -> DiagnosticsContainer { DiagnosticsContainer { diagnostics: vec![], } } pub fn add(&mut self, diagnostic: DmDiagnostic) { self.diagnostics.push(diagnostic); } } impl Into> for DiagnosticsContainer { fn into(self) -> Vec { self.diagnostics } } pub fn analyze_names( compilation_units: &mut Vec, symbol_table: &mut SymbolTable, ) -> Vec { let mut diagnostics = DiagnosticsContainer::new(); // gather symbols for compilation_unit in compilation_units.iter_mut() { gather_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); } // resolve symbols for compilation_unit in compilation_units.iter_mut() { 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::parser::{DeimosParser, Rule}; 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_no_diagnostics(sources: HashMap<&str, &str>) -> SymbolTable { 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 mut symbol_table = SymbolTable::new(); let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table); if !diagnostics.is_empty() { 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); panic!("Diagnostics was not empty!"); } for compilation_unit in &compilation_units { dbg!(compilation_unit); } symbol_table } #[test] fn params_seen() { let sources: HashMap<&str, &str> = HashMap::from([( "main.dm", indoc! {" fn main(args: Array) { let x = args; }"}, )]); assert_no_diagnostics(sources); } #[test] fn two_files() { let sources: HashMap<&str, &str> = HashMap::from([ ( "main.dm", indoc! {" use std::core::{Array, String, println}; fn main(args: Array) { println(\"Hello, World!\"); } "}, ), ( "deps.dm", indoc! {" ns std::core; pub class String {} pub class Array {} pub platform fn println(msg: String) -> Void; "}, ), ]); assert_no_diagnostics(sources); } }