#![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("")); }