From e802fc70d805571dcc6b8bb8d77b2c8c314526e1 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sun, 14 Sep 2025 08:28:06 -0500 Subject: [PATCH] Move all parser tests to generated tests. --- src/ast/{build.rs => build.rs.bak} | 0 src/ast/mod.rs | 2 +- src/ast/walk.rs | 84 ++-- src/bin/dmc/main.rs | 106 ++--- ...{name_analysis.rs => name_analysis.rs.bak} | 0 src/bin/dmc/{p3.rs => p3.rs.bak} | 0 src/bin/dmc/{unparse.rs => unparse.rs.bak} | 0 src/name_analysis/mod.rs | 430 +++++++++--------- src/parser/mod.rs | 160 +------ src/parser/tests/int_literal/hex_int | 1 + src/parser/tests/interface/simple | 3 + src/parser/tests/interface/with_alias | 4 + src/parser/tests/interface/with_op | 3 + src/parser/tests/long_literal/hex_long | 1 + 14 files changed, 326 insertions(+), 468 deletions(-) rename src/ast/{build.rs => build.rs.bak} (100%) rename src/bin/dmc/{name_analysis.rs => name_analysis.rs.bak} (100%) rename src/bin/dmc/{p3.rs => p3.rs.bak} (100%) rename src/bin/dmc/{unparse.rs => unparse.rs.bak} (100%) create mode 100644 src/parser/tests/int_literal/hex_int create mode 100644 src/parser/tests/interface/simple create mode 100644 src/parser/tests/interface/with_alias create mode 100644 src/parser/tests/interface/with_op create mode 100644 src/parser/tests/long_literal/hex_long diff --git a/src/ast/build.rs b/src/ast/build.rs.bak similarity index 100% rename from src/ast/build.rs rename to src/ast/build.rs.bak diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 9636c8b..5a22d93 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,4 +1,4 @@ -pub mod build; +// pub mod build; pub mod children; pub mod node; pub mod pretty_print; diff --git a/src/ast/walk.rs b/src/ast/walk.rs index b86e15b..d94f677 100644 --- a/src/ast/walk.rs +++ b/src/ast/walk.rs @@ -101,45 +101,45 @@ where f(node.as_node_ref()); } -#[cfg(test)] -mod tests { - use crate::ast::build::build_ast; - use crate::ast::children::NodeRef; - use crate::ast::walk::walk_depth_first; - use crate::parser::{DeimosParser, Rule}; - use indoc::indoc; - use pest::Parser; - - #[test] - fn collect_identifiers() { - let parse_result = DeimosParser::parse( - Rule::CompilationUnit, - indoc! {" - ns greeter; - - class Greeter {} - - fn main() { - let greeter = Greeter(); - } - "}, - ); - match parse_result { - Ok(cu_pairs) => { - let cu = build_ast("greeter.dm", 0, cu_pairs.into_iter().next().unwrap()); - let mut identifier_count = 0; - walk_depth_first(&cu, &mut |node_ref| match node_ref { - NodeRef::Identifier(identifier) => { - dbg!(identifier); - identifier_count += 1; - } - _ => {} - }); - assert_eq!(identifier_count, 5); - } - Err(err) => { - panic!("{}", err); - } - } - } -} +// #[cfg(test)] +// mod tests { +// use crate::ast::build::build_ast; +// use crate::ast::children::NodeRef; +// use crate::ast::walk::walk_depth_first; +// use crate::parser::{DeimosParser, Rule}; +// use indoc::indoc; +// use pest::Parser; +// +// #[test] +// fn collect_identifiers() { +// let parse_result = DeimosParser::parse( +// Rule::CompilationUnit, +// indoc! {" +// ns greeter; +// +// class Greeter {} +// +// fn main() { +// let greeter = Greeter(); +// } +// "}, +// ); +// match parse_result { +// Ok(cu_pairs) => { +// let cu = build_ast("greeter.dm", 0, cu_pairs.into_iter().next().unwrap()); +// let mut identifier_count = 0; +// walk_depth_first(&cu, &mut |node_ref| match node_ref { +// NodeRef::Identifier(identifier) => { +// dbg!(identifier); +// identifier_count += 1; +// } +// _ => {} +// }); +// assert_eq!(identifier_count, 5); +// } +// Err(err) => { +// panic!("{}", err); +// } +// } +// } +// } diff --git a/src/bin/dmc/main.rs b/src/bin/dmc/main.rs index 45ad77f..32530dc 100644 --- a/src/bin/dmc/main.rs +++ b/src/bin/dmc/main.rs @@ -1,54 +1,58 @@ -mod name_analysis; -mod p3; -mod unparse; - -use std::path::PathBuf; - -use crate::name_analysis::name_analysis; -use crate::p3::pretty_print_parse; -use crate::unparse::unparse; -use clap::{Parser, Subcommand}; - -#[derive(Debug, Parser)] -#[command(name = "dmc")] -#[command(about = "Deimos Compiler", long_about = None)] -struct Cli { - #[command(subcommand)] - command: Commands, -} - -#[derive(Debug, Subcommand)] -enum Commands { - #[command(arg_required_else_help = true)] - Unparse { - paths: Vec, - }, - P3 { - paths: Vec, - }, - NameAnalysis { - paths: Vec, - }, -} +// mod name_analysis; +// mod p3; +// mod unparse; +// +// use std::path::PathBuf; +// +// use crate::name_analysis::name_analysis; +// use crate::p3::pretty_print_parse; +// use crate::unparse::unparse; +// use clap::{Parser, Subcommand}; +// +// #[derive(Debug, Parser)] +// #[command(name = "dmc")] +// #[command(about = "Deimos Compiler", long_about = None)] +// struct Cli { +// #[command(subcommand)] +// command: Commands, +// } +// +// #[derive(Debug, Subcommand)] +// enum Commands { +// #[command(arg_required_else_help = true)] +// Unparse { +// paths: Vec, +// }, +// P3 { +// paths: Vec, +// }, +// NameAnalysis { +// paths: Vec, +// }, +// } +// +// fn main() { +// let args = Cli::parse(); +// match args.command { +// Commands::Unparse { paths } => { +// for path in paths { +// unparse(&path); +// } +// } +// Commands::P3 { paths } => { +// for path in paths { +// pretty_print_parse(&path) +// } +// } +// Commands::NameAnalysis { paths } => { +// let result = name_analysis(&paths); +// if let Err(e) = result { +// eprintln!("{}", e) +// } +// } +// } +// } fn main() { - let args = Cli::parse(); - match args.command { - Commands::Unparse { paths } => { - for path in paths { - unparse(&path); - } - } - Commands::P3 { paths } => { - for path in paths { - pretty_print_parse(&path) - } - } - Commands::NameAnalysis { paths } => { - let result = name_analysis(&paths); - if let Err(e) = result { - eprintln!("{}", e) - } - } - } + panic!("TODO") } diff --git a/src/bin/dmc/name_analysis.rs b/src/bin/dmc/name_analysis.rs.bak similarity index 100% rename from src/bin/dmc/name_analysis.rs rename to src/bin/dmc/name_analysis.rs.bak diff --git a/src/bin/dmc/p3.rs b/src/bin/dmc/p3.rs.bak similarity index 100% rename from src/bin/dmc/p3.rs rename to src/bin/dmc/p3.rs.bak diff --git a/src/bin/dmc/unparse.rs b/src/bin/dmc/unparse.rs.bak similarity index 100% rename from src/bin/dmc/unparse.rs rename to src/bin/dmc/unparse.rs.bak diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index a7ac246..ca13b36 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -51,218 +51,218 @@ pub fn analyze_names( 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); - } -} +// #[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); +// } +// } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 5ec9a8e..05d4dfe 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7,7 +7,6 @@ pub struct DeimosParser; #[cfg(test)] mod deimos_parser_tests { use crate::parser::{DeimosParser, Rule}; - use indoc::indoc; use pest::Parser; macro_rules! fail_rule { @@ -44,165 +43,8 @@ mod deimos_parser_tests { match_rule!(first; rule) } } - + mod generated_tests { include!(concat!(env!("OUT_DIR"), "/src/parser/tests/test_suites.rs")); } - - #[test] - fn hex_int() { - parses_to(Rule::IntLiteral, "0x1234abcd"); - } - - #[test] - fn hex_long() { - parses_to(Rule::LongLiteral, "0x123456789abcdefL"); - } - - #[test] - fn suffix_expression_call_single_identifier() { - parses_to(Rule::SuffixExpression, "foo()"); - } - - #[test] - fn simple_interface() { - parses_to(Rule::CompilationUnit, "pub int Simple { fn foo() -> Void }"); - } - - #[test] - fn interface_with_op() { - parses_to( - Rule::CompilationUnit, - "pub int Callable { op () () -> Void }", - ); - } - - #[test] - fn interface_with_alias() { - parses_to( - Rule::CompilationUnit, - indoc! {" - pub int Callable { - fn call() -> Void - def op () () -> Void alias call - } - "}, - ); - } - - #[test] - fn index_identifier() { - parses_to(Rule::SuffixExpression, "foo[0]"); - } - - #[test] - fn chained_index_call_on_identifier() { - parses_to(Rule::SuffixExpression, "foo[0]()"); - } - - #[test] - fn if_statement() { - parses_to( - Rule::IfStatement, - indoc! {" - if (foo == 42) { - bar() - }"}, - ) - } - - // #[test] - // fn if_else_statement() { - // parses_to( - // Rule::IfElseStatement, - // indoc! {" - // if (foo == 42) { - // bar() - // } else { - // baz() - // }"}, - // ) - // } - // - // #[test] - // fn if_else_if_statement() { - // parses_to( - // Rule::IfElseStatement, - // indoc! {" - // if (foo == 42) { - // bar() - // } else if (foo == 16) { - // baz() - // }"}, - // ) - // } - // - // #[test] - // fn if_else_if_else_statement() { - // parses_to( - // Rule::IfElseStatement, - // indoc! {" - // if (foo == 42) { - // foo() - // } else if (foo == 16) { - // baz() - // } else { - // fizz() - // }"}, - // ) - // } - - #[test] - fn while_statement() { - parses_to(Rule::WhileStatement, "while (foo) { bar() }"); - } - - #[test] - fn for_statement() { - parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }"); - } - - #[test] - fn if_statement_with_call_condition() { - parses_to( - Rule::IfStatement, - indoc! {" - if (foo()) { - bar() - } - "}, - ) - } - - #[test] - fn while_statement_with_call_condition() { - parses_to(Rule::WhileStatement, "while (foo()) { bar(); }") - } - - #[test] - fn for_statement_with_call_iterator() { - parses_to( - Rule::ForStatement, - indoc! {" - for (foo in bar()) { - baz(foo); - } - "}, - ) - } - - #[test] - fn use_statement() { - parses_to(Rule::UseStatement, "use std::core::println"); - } - - #[test] - fn use_star() { - parses_to(Rule::UseStatement, "use std::core::*") - } - - #[test] - fn use_list() { - parses_to(Rule::UseStatement, "use std::core::{print, println}"); - } } diff --git a/src/parser/tests/int_literal/hex_int b/src/parser/tests/int_literal/hex_int new file mode 100644 index 0000000..b14eb07 --- /dev/null +++ b/src/parser/tests/int_literal/hex_int @@ -0,0 +1 @@ +0x1234abcd \ No newline at end of file diff --git a/src/parser/tests/interface/simple b/src/parser/tests/interface/simple new file mode 100644 index 0000000..34abeab --- /dev/null +++ b/src/parser/tests/interface/simple @@ -0,0 +1,3 @@ +pub int Simple + fn foo() -> Void +end \ No newline at end of file diff --git a/src/parser/tests/interface/with_alias b/src/parser/tests/interface/with_alias new file mode 100644 index 0000000..a7145c4 --- /dev/null +++ b/src/parser/tests/interface/with_alias @@ -0,0 +1,4 @@ +pub int Callable + fn call() -> Void + def op () () -> Void alias call +end \ No newline at end of file diff --git a/src/parser/tests/interface/with_op b/src/parser/tests/interface/with_op new file mode 100644 index 0000000..e976825 --- /dev/null +++ b/src/parser/tests/interface/with_op @@ -0,0 +1,3 @@ +pub int Callable + op () () -> Void +end \ No newline at end of file diff --git a/src/parser/tests/long_literal/hex_long b/src/parser/tests/long_literal/hex_long new file mode 100644 index 0000000..6d82ca6 --- /dev/null +++ b/src/parser/tests/long_literal/hex_long @@ -0,0 +1 @@ +0x123456789abcdefL \ No newline at end of file