rott/dev_tests/src/verify_expr.rs

143 lines
3.7 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)] = &[
// L0001: invalid or unknown token
(
"files/L0001_01.uc",
"`",
),
// L0002: unexpected closing delimiter
(
"files/L0002_01.uc",
"]",
),
// L0003: unclosed delimiter before later closing delimiter
//
// The `}` can still recover by matching the earlier `{`.
(
"files/L0003_01.uc",
"{\n foo(\n}\n",
),
// L0004: mismatched closing delimiter
(
"files/L0004_01.uc",
"(]",
),
// L0005: unclosed delimiter at end of file
(
"files/L0005_01.uc",
"foo(",
),
// Mixed recovery case:
//
// `)` recovers by matching `(` after treating `[` as unclosed;
// the following `]` is then unexpected.
(
"files/L_mixed_01.uc",
"([)]",
),
];
/// 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 = false;
/// If true, print the parsed expression using Debug formatting.
const PRINT_PARSED_EXPR: bool = false;
/// If true, print diagnostics even when parsing returned a value.
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 ALWAYS_PRINT_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>"));
}