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