Move all parser tests to generated tests.

This commit is contained in:
Jesse Brault 2025-09-14 08:28:06 -05:00
parent c453557deb
commit e802fc70d8
14 changed files with 326 additions and 468 deletions

View File

@ -1,4 +1,4 @@
pub mod build; // pub mod build;
pub mod children; pub mod children;
pub mod node; pub mod node;
pub mod pretty_print; pub mod pretty_print;

View File

@ -101,45 +101,45 @@ where
f(node.as_node_ref()); f(node.as_node_ref());
} }
#[cfg(test)] // #[cfg(test)]
mod tests { // mod tests {
use crate::ast::build::build_ast; // use crate::ast::build::build_ast;
use crate::ast::children::NodeRef; // use crate::ast::children::NodeRef;
use crate::ast::walk::walk_depth_first; // use crate::ast::walk::walk_depth_first;
use crate::parser::{DeimosParser, Rule}; // use crate::parser::{DeimosParser, Rule};
use indoc::indoc; // use indoc::indoc;
use pest::Parser; // use pest::Parser;
//
#[test] // #[test]
fn collect_identifiers() { // fn collect_identifiers() {
let parse_result = DeimosParser::parse( // let parse_result = DeimosParser::parse(
Rule::CompilationUnit, // Rule::CompilationUnit,
indoc! {" // indoc! {"
ns greeter; // ns greeter;
//
class Greeter {} // class Greeter {}
//
fn main() { // fn main() {
let greeter = Greeter(); // let greeter = Greeter();
} // }
"}, // "},
); // );
match parse_result { // match parse_result {
Ok(cu_pairs) => { // Ok(cu_pairs) => {
let cu = build_ast("greeter.dm", 0, cu_pairs.into_iter().next().unwrap()); // let cu = build_ast("greeter.dm", 0, cu_pairs.into_iter().next().unwrap());
let mut identifier_count = 0; // let mut identifier_count = 0;
walk_depth_first(&cu, &mut |node_ref| match node_ref { // walk_depth_first(&cu, &mut |node_ref| match node_ref {
NodeRef::Identifier(identifier) => { // NodeRef::Identifier(identifier) => {
dbg!(identifier); // dbg!(identifier);
identifier_count += 1; // identifier_count += 1;
} // }
_ => {} // _ => {}
}); // });
assert_eq!(identifier_count, 5); // assert_eq!(identifier_count, 5);
} // }
Err(err) => { // Err(err) => {
panic!("{}", err); // panic!("{}", err);
} // }
} // }
} // }
} // }

View File

@ -1,54 +1,58 @@
mod name_analysis; // mod name_analysis;
mod p3; // mod p3;
mod unparse; // mod unparse;
//
use std::path::PathBuf; // use std::path::PathBuf;
//
use crate::name_analysis::name_analysis; // use crate::name_analysis::name_analysis;
use crate::p3::pretty_print_parse; // use crate::p3::pretty_print_parse;
use crate::unparse::unparse; // use crate::unparse::unparse;
use clap::{Parser, Subcommand}; // use clap::{Parser, Subcommand};
//
#[derive(Debug, Parser)] // #[derive(Debug, Parser)]
#[command(name = "dmc")] // #[command(name = "dmc")]
#[command(about = "Deimos Compiler", long_about = None)] // #[command(about = "Deimos Compiler", long_about = None)]
struct Cli { // struct Cli {
#[command(subcommand)] // #[command(subcommand)]
command: Commands, // command: Commands,
} // }
//
#[derive(Debug, Subcommand)] // #[derive(Debug, Subcommand)]
enum Commands { // enum Commands {
#[command(arg_required_else_help = true)] // #[command(arg_required_else_help = true)]
Unparse { // Unparse {
paths: Vec<PathBuf>, // paths: Vec<PathBuf>,
}, // },
P3 { // P3 {
paths: Vec<PathBuf>, // paths: Vec<PathBuf>,
}, // },
NameAnalysis { // NameAnalysis {
paths: Vec<PathBuf>, // paths: Vec<PathBuf>,
}, // },
} // }
//
// 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() { fn main() {
let args = Cli::parse(); panic!("TODO")
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)
}
}
}
} }

View File

@ -51,218 +51,218 @@ pub fn analyze_names(
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::ast::children::NodeRef;
use crate::ast::walk::walk_depth_first; // use crate::ast::walk::walk_depth_first;
use crate::parser::{DeimosParser, Rule}; // use crate::parser::{DeimosParser, Rule};
use crate::std_core::add_std_core_symbols; // use crate::std_core::add_std_core_symbols;
use codespan_reporting::files::SimpleFiles; // use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term; // use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; // use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use indoc::indoc; // use indoc::indoc;
use pest::Parser; // use pest::Parser;
use std::collections::HashMap; // use std::collections::HashMap;
//
fn assert_number_of_diagnostics( // fn assert_number_of_diagnostics(
sources: HashMap<&str, &str>, // sources: HashMap<&str, &str>,
symbol_table: &mut SymbolTable, // symbol_table: &mut SymbolTable,
n_diagnostics: usize, // n_diagnostics: usize,
) -> Vec<CompilationUnit> { // ) -> Vec<CompilationUnit> {
let mut files = SimpleFiles::new(); // let mut files = SimpleFiles::new();
let mut compilation_units = vec![]; // let mut compilation_units = vec![];
//
for (file_name, source) in sources { // for (file_name, source) in sources {
let file_id = files.add(file_name, source); // let file_id = files.add(file_name, source);
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source); // let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
if let Err(err) = &parse_result { // if let Err(err) = &parse_result {
panic!("{}", err); // panic!("{}", err);
} // }
let mut pairs = parse_result.unwrap(); // let mut pairs = parse_result.unwrap();
if pairs.as_str().trim() != source.trim() { // if pairs.as_str().trim() != source.trim() {
panic!("Parsing did not consume entire input."); // panic!("Parsing did not consume entire input.");
} // }
//
compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap())); // compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap()));
} // }
//
let diagnostics = analyze_names(&mut compilation_units, symbol_table); // let diagnostics = analyze_names(&mut compilation_units, symbol_table);
//
if diagnostics.len() != n_diagnostics { // if diagnostics.len() != n_diagnostics {
let writer = StandardStream::stderr(ColorChoice::Always); // let writer = StandardStream::stderr(ColorChoice::Always);
let config = term::Config::default(); // let config = term::Config::default();
//
for diagnostic in &diagnostics { // for diagnostic in &diagnostics {
term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap(); // term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
} // }
//
eprintln!("{}", symbol_table); // eprintln!("{}", symbol_table);
} // }
//
assert_eq!(n_diagnostics, diagnostics.len()); // assert_eq!(n_diagnostics, diagnostics.len());
//
compilation_units // compilation_units
} // }
//
fn assert_no_diagnostics( // fn assert_no_diagnostics(
sources: HashMap<&str, &str>, // sources: HashMap<&str, &str>,
symbol_table: &mut SymbolTable, // symbol_table: &mut SymbolTable,
) -> Vec<CompilationUnit> { // ) -> Vec<CompilationUnit> {
assert_number_of_diagnostics(sources, symbol_table, 0) // assert_number_of_diagnostics(sources, symbol_table, 0)
} // }
//
fn assert_saved_symbols(compilation_unit: &CompilationUnit) { // fn assert_saved_symbols(compilation_unit: &CompilationUnit) {
walk_depth_first(compilation_unit, &mut |node_ref| match node_ref { // walk_depth_first(compilation_unit, &mut |node_ref| match node_ref {
NodeRef::Identifier(identifier) => { // NodeRef::Identifier(identifier) => {
if identifier.saved_symbol().is_none() { // if identifier.saved_symbol().is_none() {
panic!("{:?} does not have a saved symbol.", identifier) // panic!("{:?} does not have a saved symbol.", identifier)
} // }
} // }
NodeRef::FullyQualifiedName(fqn) => { // NodeRef::FullyQualifiedName(fqn) => {
if fqn.saved_symbol().is_none() { // if fqn.saved_symbol().is_none() {
panic!("{:?} does not have a saved symbol.", fqn) // panic!("{:?} does not have a saved symbol.", fqn)
} // }
} // }
NodeRef::UseStatement(use_statement) => match use_statement { // NodeRef::UseStatement(use_statement) => match use_statement {
_ => todo!(), // _ => todo!(),
}, // },
_ => {} // _ => {}
}) // })
} // }
//
fn assert_resolved_symbols(compilation_unit: &CompilationUnit) { // fn assert_resolved_symbols(compilation_unit: &CompilationUnit) {
walk_depth_first(compilation_unit, &mut |node_ref| match node_ref { // walk_depth_first(compilation_unit, &mut |node_ref| match node_ref {
NodeRef::UseStatement(use_statement) => match use_statement { // NodeRef::UseStatement(use_statement) => match use_statement {
_ => todo!(), // _ => todo!(),
}, // },
_ => {} // _ => {}
}) // })
} // }
//
#[test] // #[test]
fn params_seen() { // fn params_seen() {
let sources: HashMap<&str, &str> = HashMap::from([( // let sources: HashMap<&str, &str> = HashMap::from([(
"main.dm", // "main.dm",
indoc! {" // indoc! {"
fn main(args: Array<String>) { // fn main(args: Array<String>) {
let x = args; // let x = args;
}"}, // }"},
)]); // )]);
//
let cus = assert_no_diagnostics(sources, &mut SymbolTable::new()); // let cus = assert_no_diagnostics(sources, &mut SymbolTable::new());
for ref cu in cus { // for ref cu in cus {
assert_saved_symbols(cu); // assert_saved_symbols(cu);
} // }
} // }
//
#[test] // #[test]
fn two_files() { // fn two_files() {
let sources: HashMap<&str, &str> = HashMap::from([ // let sources: HashMap<&str, &str> = HashMap::from([
( // (
"main.dm", // "main.dm",
indoc! {" // indoc! {"
use test::Greeter; // use test::Greeter;
"}, // "},
), // ),
( // (
"deps.dm", // "deps.dm",
indoc! {" // indoc! {"
ns test; // ns test;
//
pub class Greeter {} // pub class Greeter {}
"}, // "},
), // ),
]); // ]);
//
let cus = assert_no_diagnostics(sources, &mut SymbolTable::new()); // let cus = assert_no_diagnostics(sources, &mut SymbolTable::new());
for ref cu in cus { // for ref cu in cus {
assert_saved_symbols(cu); // assert_saved_symbols(cu);
assert_resolved_symbols(cu); // assert_resolved_symbols(cu);
} // }
} // }
//
#[test] // #[test]
fn sees_std_core_println() { // fn sees_std_core_println() {
let sources: HashMap<&str, &str> = HashMap::from([( // let sources: HashMap<&str, &str> = HashMap::from([(
"main.dm", // "main.dm",
indoc! {" // indoc! {"
fn main(args: Array<String>) { // fn main(args: Array<String>) {
println(args) // println(args)
} // }
"}, // "},
)]); // )]);
//
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 cus = assert_no_diagnostics(sources, &mut symbol_table); // let cus = assert_no_diagnostics(sources, &mut symbol_table);
for ref cu in cus { // for ref cu in cus {
assert_saved_symbols(cu); // assert_saved_symbols(cu);
assert_resolved_symbols(cu); // assert_resolved_symbols(cu);
} // }
} // }
//
#[test] // #[test]
fn sees_duplicate_fn() { // fn sees_duplicate_fn() {
let sources: HashMap<&str, &str> = HashMap::from([( // let sources: HashMap<&str, &str> = HashMap::from([(
"main.dm", // "main.dm",
indoc! {" // indoc! {"
fn main(args: Array<String>) {} // fn main(args: Array<String>) {}
fn main(args: Array<String>) {} // fn main(args: Array<String>) {}
"}, // "},
)]); // )]);
assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1); // assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
} // }
//
#[test] // #[test]
fn use_class_from_other_file() { // fn use_class_from_other_file() {
let sources: HashMap<&str, &str> = HashMap::from([ // let sources: HashMap<&str, &str> = HashMap::from([
( // (
"main.dm", // "main.dm",
indoc! {" // indoc! {"
use greeter::Greeter; // use greeter::Greeter;
//
fn test(greeter: Greeter) {} // fn test(greeter: Greeter) {}
"}, // "},
), // ),
( // (
"greeter.dm", // "greeter.dm",
indoc! {" // indoc! {"
ns greeter; // ns greeter;
//
class Greeter {} // class Greeter {}
"}, // "},
), // ),
]); // ]);
let mut symbol_table = SymbolTable::new(); // let mut symbol_table = SymbolTable::new();
let cus = assert_no_diagnostics(sources, &mut symbol_table); // let cus = assert_no_diagnostics(sources, &mut symbol_table);
for ref cu in cus { // for ref cu in cus {
assert_saved_symbols(cu); // assert_saved_symbols(cu);
assert_resolved_symbols(cu); // assert_resolved_symbols(cu);
} // }
} // }
//
#[test] // #[test]
fn shadow_import() { // fn shadow_import() {
let sources: HashMap<&str, &str> = HashMap::from([ // let sources: HashMap<&str, &str> = HashMap::from([
( // (
"main.dm", // "main.dm",
indoc! {" // indoc! {"
use greeter::Greeter; // use greeter::Greeter;
//
class Greeter {} // class Greeter {}
"}, // "},
), // ),
( // (
"greeter.dm", // "greeter.dm",
indoc! {" // indoc! {"
ns greeter; // ns greeter;
//
class Greeter {} // class Greeter {}
"}, // "},
), // ),
]); // ]);
assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1); // assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
} // }
} // }

View File

@ -7,7 +7,6 @@ pub struct DeimosParser;
#[cfg(test)] #[cfg(test)]
mod deimos_parser_tests { mod deimos_parser_tests {
use crate::parser::{DeimosParser, Rule}; use crate::parser::{DeimosParser, Rule};
use indoc::indoc;
use pest::Parser; use pest::Parser;
macro_rules! fail_rule { macro_rules! fail_rule {
@ -44,165 +43,8 @@ mod deimos_parser_tests {
match_rule!(first; rule) match_rule!(first; rule)
} }
} }
mod generated_tests { mod generated_tests {
include!(concat!(env!("OUT_DIR"), "/src/parser/tests/test_suites.rs")); 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}");
}
} }

View File

@ -0,0 +1 @@
0x1234abcd

View File

@ -0,0 +1,3 @@
pub int Simple
fn foo() -> Void
end

View File

@ -0,0 +1,4 @@
pub int Callable
fn call() -> Void
def op () () -> Void alias call
end

View File

@ -0,0 +1,3 @@
pub int Callable
op () () -> Void
end

View File

@ -0,0 +1 @@
0x123456789abcdefL