Re-enable tests for name analysis. Currently failing.

This commit is contained in:
Jesse Brault 2025-10-29 12:13:39 -05:00
parent d653d26e14
commit e5c5be6d95
4 changed files with 195 additions and 239 deletions

View File

@ -79,9 +79,9 @@ pub mod build {
include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs")); include!(concat!(env!("OUT_DIR"), "/src/ast/build.rs"));
pub fn build_ast(file_id: usize, parsed_pairs: &mut Pairs<Rule>) -> Box<CompilationUnit> { pub fn build_ast(file_id: usize, parsed_pairs: &mut Pairs<Rule>) -> CompilationUnit {
let compilation_unit_pair = parsed_pairs.next().unwrap(); let compilation_unit_pair = parsed_pairs.next().unwrap();
Box::new(build_compilation_unit(file_id, compilation_unit_pair)) build_compilation_unit(file_id, compilation_unit_pair)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -3,40 +3,69 @@ use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use deimos::ast::build::build_ast; use deimos::ast::build::build_ast;
use deimos::name_analysis::analyze_names; use deimos::name_analysis::analyze_names;
use deimos::name_analysis::symbol_table::symbol_tree::SymbolTree;
use deimos::name_analysis::symbol_table::SymbolTable; use deimos::name_analysis::symbol_table::SymbolTable;
use deimos::parser::{DeimosParser, Rule}; use deimos::parser::{DeimosParser, Rule};
use deimos::std_core::add_std_core_symbols; use deimos::std_core::add_std_core_symbols;
use pest::Parser; use pest::Parser;
use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};
use std::path::PathBuf; use std::path::PathBuf;
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> { struct ParseErrors {
let mut compilation_units = vec![]; errors: Vec<pest::error::Error<Rule>>,
let mut files: SimpleFiles<String, String> = SimpleFiles::new(); }
impl Debug for ParseErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
impl Display for ParseErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "There were errors during parsing.")?;
for parse_error in &self.errors {
writeln!(f, "{}", parse_error)?;
}
Ok(())
}
}
impl std::error::Error for ParseErrors {}
pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>> {
let mut paths_and_sources: HashMap<String, String> = HashMap::new();
for path in paths { for path in paths {
let src = std::fs::read_to_string(path).unwrap(); let src = std::fs::read_to_string(path).unwrap();
let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src); paths_and_sources.insert(path.display().to_string(), src);
let file_id = files.add(path.display().to_string(), src.clone()); // I don't love this clone }
let mut compilation_units = vec![];
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
let mut parse_errors = vec![];
for (path, source) in &paths_and_sources {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
match parse_result { match parse_result {
Ok(mut pairs) => { Ok(mut pairs) => {
let file_id = files.add(path, source);
let compilation_unit = build_ast(file_id, &mut pairs); let compilation_unit = build_ast(file_id, &mut pairs);
compilation_units.push(compilation_unit); compilation_units.push(compilation_unit);
Ok::<(), Box<dyn std::error::Error>>(())
} }
Err(e) => Err(e.into()), Err(error) => {
}?; parse_errors.push(error);
}
}
}
if !parse_errors.is_empty() {
return Err(Box::new(ParseErrors { errors: parse_errors }));
} }
let mut symbol_table = SymbolTable::new(); let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols."); add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
let diagnostics = analyze_names( let diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table);
&mut compilation_units,
&files,
&mut symbol_table,
);
if diagnostics.is_empty() { if diagnostics.is_empty() {
println!("Name analysis complete."); println!("Name analysis complete.");
println!("{}", symbol_table); println!("{}", symbol_table);

View File

@ -1,4 +1,9 @@
use crate::ast::node::{CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody, GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameters, PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement, UseStatementIdentifier, UseStatementPrefix}; use crate::ast::node::{
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody,
GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameters,
PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement,
UseStatementIdentifier, UseStatementPrefix,
};
use crate::diagnostic::DmDiagnostic; use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol; use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol;
@ -9,8 +14,10 @@ use crate::name_analysis::symbol::primitive_type_symbol::PrimitiveTypeSymbol;
use crate::name_analysis::symbol::source_definition::SourceDefinition; use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::type_symbol::TypeSymbol; use crate::name_analysis::symbol::type_symbol::TypeSymbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; use crate::name_analysis::symbol_table::SymbolTable;
use crate::name_analysis::util::{format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts}; use crate::name_analysis::util::{
format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts,
};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -143,7 +150,9 @@ fn na_p1_star_use_statement(
let to_insert = StarUseSymbol::new( let to_insert = StarUseSymbol::new(
&fqn_parts, &fqn_parts,
Some(SourceDefinition::from_star_use_statement(star_use_statement)) Some(SourceDefinition::from_star_use_statement(
star_use_statement,
)),
); );
match symbol_table.insert_star_use_symbol(to_insert) { match symbol_table.insert_star_use_symbol(to_insert) {
Ok(star_use_symbol) => { Ok(star_use_symbol) => {

View File

@ -36,8 +36,11 @@ pub mod symbol;
pub mod symbol_table; pub mod symbol_table;
mod util; mod util;
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( pub fn analyze_names<
compilation_units: &mut Vec<Box<CompilationUnit>>, 'a,
F: Files<'a, FileId = usize, Name = &'a str, Source = &'a str> + ?Sized,
>(
compilation_units: &mut Vec<CompilationUnit>,
files: &'a F, files: &'a F,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
) -> Vec<DmDiagnostic> { ) -> Vec<DmDiagnostic> {
@ -46,7 +49,7 @@ pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
// gather symbols // gather symbols
for compilation_unit in compilation_units.iter_mut() { for compilation_unit in compilation_units.iter_mut() {
let file_name = files.name(compilation_unit.file_id()).unwrap(); let file_name = files.name(compilation_unit.file_id()).unwrap();
na_p1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics); na_p1_compilation_unit(file_name, compilation_unit, symbol_table, &mut diagnostics);
} }
// resolve symbols // resolve symbols
@ -57,218 +60,133 @@ pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
diagnostics.into() diagnostics.into()
} }
// #[cfg(test)] #[cfg(test)]
// mod tests { mod tests {
// use super::*; use super::*;
// use crate::ast::build::build_ast; use crate::ast::build::build_ast;
// use crate::ast::children::NodeRef; use crate::parser::{DeimosParser, Rule};
// use crate::ast::walk::walk_depth_first; use crate::std_core::add_std_core_symbols;
// use crate::parser::{DeimosParser, Rule}; use codespan_reporting::files::SimpleFiles;
// use crate::std_core::add_std_core_symbols; use codespan_reporting::term;
// use codespan_reporting::files::SimpleFiles; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
// use codespan_reporting::term; use pest::Parser;
// use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use std::collections::HashMap;
// use indoc::indoc;
// use pest::Parser; fn parse_compilation_units<'a>(
// use std::collections::HashMap; files: &mut SimpleFiles<&'a str, &'a str>,
// sources: HashMap<&'a str, &'a str>,
// fn assert_number_of_diagnostics( ) -> Vec<CompilationUnit> {
// sources: HashMap<&str, &str>, let mut compilation_units: Vec<CompilationUnit> = vec![];
// symbol_table: &mut SymbolTable,
// n_diagnostics: usize, for (file_name, source) in sources {
// ) -> Vec<CompilationUnit> { let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
// let mut files = SimpleFiles::new(); if let Err(err) = &parse_result {
// let mut compilation_units = vec![]; panic!("{}", err);
// }
// for (file_name, source) in sources { let mut pairs = parse_result.unwrap();
// let file_id = files.add(file_name, source); if pairs.as_str().trim() != source.trim() {
// let parse_result = DeimosParser::parse(Rule::CompilationUnit, source); panic!("Parsing did not consume entire input.");
// if let Err(err) = &parse_result { }
// panic!("{}", err); let file_id = files.add(file_name, source);
// } compilation_units.push(build_ast(file_id, &mut pairs));
// let mut pairs = parse_result.unwrap(); }
// if pairs.as_str().trim() != source.trim() {
// panic!("Parsing did not consume entire input."); compilation_units
// } }
//
// compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap())); fn assert_number_of_diagnostics<'a>(
// } sources: HashMap<&'a str, &'a str>,
// symbol_table: &mut SymbolTable,
// let diagnostics = analyze_names(&mut compilation_units, symbol_table); number_of_diagnostics: usize,
// ) -> Vec<CompilationUnit> {
// if diagnostics.len() != n_diagnostics { let mut files = SimpleFiles::<&'a str, &'a str>::new();
// let writer = StandardStream::stderr(ColorChoice::Always); let mut compilation_units = parse_compilation_units(&mut files, sources);
// let config = term::Config::default();
// let diagnostics = analyze_names(&mut compilation_units, &files, symbol_table);
// for diagnostic in &diagnostics {
// term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap(); if diagnostics.len() != number_of_diagnostics {
// } let writer = StandardStream::stderr(ColorChoice::Always);
// let config = term::Config::default();
// eprintln!("{}", symbol_table);
// } for diagnostic in &diagnostics {
// term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
// assert_eq!(n_diagnostics, diagnostics.len()); }
//
// compilation_units eprintln!("{}", symbol_table);
// } }
//
// fn assert_no_diagnostics( assert_eq!(number_of_diagnostics, diagnostics.len());
// sources: HashMap<&str, &str>,
// symbol_table: &mut SymbolTable, compilation_units
// ) -> Vec<CompilationUnit> { }
// assert_number_of_diagnostics(sources, symbol_table, 0)
// } fn assert_no_diagnostics(
// sources: HashMap<&str, &str>,
// fn assert_saved_symbols(compilation_unit: &CompilationUnit) { symbol_table: &mut SymbolTable,
// walk_depth_first(compilation_unit, &mut |node_ref| match node_ref { ) -> Vec<CompilationUnit> {
// NodeRef::Identifier(identifier) => { assert_number_of_diagnostics(sources, symbol_table, 0)
// if identifier.saved_symbol().is_none() { }
// panic!("{:?} does not have a saved symbol.", identifier)
// } #[test]
// } fn params_seen() {
// NodeRef::FullyQualifiedName(fqn) => { let sources = HashMap::from([(
// if fqn.saved_symbol().is_none() { "main.dm",
// panic!("{:?} does not have a saved symbol.", fqn) "
// } fn main(args: Array<String>)
// } let x = args
// NodeRef::UseStatement(use_statement) => match use_statement { end
// _ => todo!(), ",
// }, )]);
// _ => {}
// }) assert_no_diagnostics(sources, &mut SymbolTable::new());
// } }
//
// fn assert_resolved_symbols(compilation_unit: &CompilationUnit) { #[test]
// walk_depth_first(compilation_unit, &mut |node_ref| match node_ref { fn two_files() {
// NodeRef::UseStatement(use_statement) => match use_statement { let sources = HashMap::from([
// _ => todo!(), (
// }, "main.dm",
// _ => {} "
// }) use test::Greeter
// } ",
// ),
// #[test] (
// fn params_seen() { "deps.dm",
// let sources: HashMap<&str, &str> = HashMap::from([( "
// "main.dm", ns test
// indoc! {"
// fn main(args: Array<String>) { pub class Greeter end
// let x = args; ",
// }"}, ),
// )]); ]);
// assert_no_diagnostics(sources, &mut SymbolTable::new());
// let cus = assert_no_diagnostics(sources, &mut SymbolTable::new()); }
// for ref cu in cus {
// assert_saved_symbols(cu); #[test]
// } fn sees_std_core_println() {
// } let sources: HashMap<&str, &str> = HashMap::from([(
// "main.dm",
// #[test] "
// fn two_files() { fn main(args: Array<String>)
// let sources: HashMap<&str, &str> = HashMap::from([ std::core::println args
// ( end
// "main.dm", ",
// indoc! {" )]);
// use test::Greeter;
// "}, let mut symbol_table = SymbolTable::new();
// ), add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
// ( assert_no_diagnostics(sources, &mut symbol_table);
// "deps.dm", }
// indoc! {"
// ns test; #[test]
// fn sees_duplicate_fn() {
// pub class Greeter {} let sources: HashMap<&str, &str> = HashMap::from([(
// "}, "main.dm",
// ), "
// ]); fn main(args: Array<String>) end
// fn main(args: Array<String>) end
// let cus = assert_no_diagnostics(sources, &mut SymbolTable::new()); ",
// for ref cu in cus { )]);
// assert_saved_symbols(cu); assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
// assert_resolved_symbols(cu); }
// } }
// }
//
// #[test]
// fn sees_std_core_println() {
// let sources: HashMap<&str, &str> = HashMap::from([(
// "main.dm",
// indoc! {"
// fn main(args: Array<String>) {
// 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<String>) {}
// fn main(args: Array<String>) {}
// "},
// )]);
// 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);
// }
// }