142 lines
4.1 KiB
Rust
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>"));
|
|
}
|