rott/dev_tests/src/verify_expr.rs

142 lines
4.1 KiB
Rust

#![allow(
clippy::all,
clippy::pedantic,
clippy::nursery,
clippy::cargo,
clippy::restriction
)]
use rottlib::arena::Arena;
use rottlib::diagnostics::Diagnostic;
use rottlib::lexer::TokenizedFile;
use rottlib::parser::Parser;
/// Lexer-focused fixtures.
///
/// Keep these small: the goal is to inspect lexer diagnostics and delimiter
/// recovery behavior, not full parser behavior.
const TEST_CASES: &[(&str, &str)] = &[
// P0031 - FunctionCallArgumentMissingComma
(
"files/P0031_01.uc",
"{\n Func(A B);\n Log(\"after\");\n}\n",
),
(
"files/P0031_02.uc",
"{\n Func\n (A 123);\n Log(\"after\");\n}\n",
),
(
"files/P0031_03.uc",
"{\n Func(\n A\n new SomeClass\n );\n Log(\"after\");\n}\n",
),
// P0032 - FunctionCallMissingClosingParenthesis
("files/P0032_01.uc", "Func("),
("files/P0032_02.uc", "Func\n(\n A,"),
("files/P0032_03.uc", "Func(A,\n B,"),
(
"files/P0032_04.uc",
"{\n Func\n (\n A,\n B,\n",
),
// P0033 - FunctionCallUnexpectedTokenInArgumentList
(
"files/P0033_01.uc",
"{\n Func(A #, B);\n Log(\"after\");\n}\n",
),
(
"files/P0033_02.uc",
"{\n Func\n (A\n :,\n B);\n Log(\"after\");\n}\n",
),
(
"files/P0033_03.uc",
"{\n Func(\n A ?\n , B\n );\n Log(\"after\");\n}\n",
),
(
"files/P0033_04.uc",
"{\n Func\n (\n A\n #,\n B\n );\n Log(\"after\");\n}\n",
),
];
/// If true, also run the parser after tokenization.
///
/// For lexer-focused fixtures this is usually noisy, so keep it off unless you
/// want to inspect how parser recovery behaves after lexer diagnostics.
const RUN_PARSER: bool = true;
/// If true, print the parsed expression using Debug formatting.
const PRINT_PARSED_EXPR: bool = false;
const PRINT_LEXER_DIAGNOSTICS: bool = false;
const ALWAYS_PRINT_DIAGNOSTICS: bool = true;
fn main() {
let arena = Arena::new();
let mut had_any_problem = false;
for (idx, (label, source)) in TEST_CASES.iter().enumerate() {
println!("============================================================");
println!("Case {}: {}", idx + 1, label);
println!("------------------------------------------------------------");
let tf = TokenizedFile::tokenize(source);
let lexer_diagnostics = tf.diagnostics();
if lexer_diagnostics.is_empty() {
println!("Lexer diagnostics: none");
} else {
had_any_problem = true;
if PRINT_LEXER_DIAGNOSTICS {
println!("Lexer diagnostics:");
for diag in lexer_diagnostics {
render_diagnostic(diag, &tf, Some(label), false);
}
}
}
if RUN_PARSER {
let mut parser = Parser::new(&tf, &arena);
let expr = parser.parse_expression();
if PRINT_PARSED_EXPR {
println!("Parsed expression:");
println!("{expr:#?}");
}
if parser.diagnostics.is_empty() {
println!("Parser diagnostics: none");
} else {
had_any_problem = true;
if ALWAYS_PRINT_DIAGNOSTICS {
println!("Parser diagnostics:");
for diag in &parser.diagnostics {
render_diagnostic(diag, &tf, Some(label), false);
}
}
}
}
println!();
}
println!("============================================================");
if had_any_problem {
println!("Done. At least one case had lexer or parser diagnostics.");
std::process::exit(1);
} else {
println!("Done. All cases completed without diagnostics.");
}
}
fn render_diagnostic(
diag: &Diagnostic,
file: &TokenizedFile<'_>,
file_name: Option<&str>,
_colors: bool,
) {
diag.render(file, file_name.unwrap_or("<default>"));
}