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 node;
pub mod pretty_print;

View File

@ -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);
// }
// }
// }
// }

View File

@ -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<PathBuf>,
},
P3 {
paths: Vec<PathBuf>,
},
NameAnalysis {
paths: Vec<PathBuf>,
},
}
// 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<PathBuf>,
// },
// P3 {
// paths: Vec<PathBuf>,
// },
// NameAnalysis {
// 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() {
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")
}

View File

@ -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<CompilationUnit> {
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<CompilationUnit> {
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<String>) {
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<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);
}
}
// #[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<CompilationUnit> {
// 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<CompilationUnit> {
// 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<String>) {
// 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<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);
// }
// }

View File

@ -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}");
}
}

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