use colored::Colorize; use rusche::{tokenize, Evaluator, LexError, Loc, ParseError, Parser}; use rustyline::{error::ReadlineError, DefaultEditor}; use crate::print_error; pub fn run_repl(evaluator: Evaluator) { print_logo(); let mut rl = DefaultEditor::new().expect("Failed to initialize line reader!"); let mut src = String::new(); let mut consumed_lines: usize = 0; let mut parser = Parser::new(); loop { let line = src.lines().count(); let prompt = if line == consumed_lines { format!("repl:{:03}❯ ", line + 1) } else { debug_assert!(parser.is_parsing()); format!("....:{:03}❯ ", line + 1) }; match rl.readline(&prompt) { Ok(text) => { let _ = rl.add_history_entry(text.as_str()); let loc = Some(Loc::new(line, 0)); let res = tokenize(&text, loc); match res { Ok(tokens) => parser.add_tokens(tokens), Err(err) => { let error_src = src.clone() + &text; match err { LexError::InvalidNumber(span) => { print_error("invalid number", &error_src, Some(span)) } LexError::IncompleteString(span) => { print_error("incomplete string", &error_src, Some(span)) } } continue; } } src.push_str(&text); src.push_str("\n"); loop { match parser.parse() { Ok(None) => { consumed_lines = src.lines().count(); break; } Ok(Some(expr)) => match evaluator.eval(&expr) { Ok(result) => { println!("{}", result.to_string().green()); } Err(error) => { print_error(&error.message, &src, error.span); } }, Err(ParseError::IncompleteExpr(_)) => break, Err(ParseError::UnexpectedToken(token)) => { parser.reset(); print_error( &format!("unexpected token: \"{token}\""), &src, Some(token.span()), ); consumed_lines = src.lines().count(); } } } } Err(ReadlineError::Eof) => { break; } Err(error) => { eprintln!("{error}"); break; } } } } #[rustfmt::skip] fn print_logo() { println!(" {} ", r" ____ __ ".bold().cyan()); println!(" {} ", r" / __ \__ ____________/ /_ ___ ".bold().cyan()); println!(" {} ", r" / /_/ / / / / ___/ ___/ __ \/ _ \".bold().cyan()); println!("Welcome to{} !", r" / _, _/ /_/ (__ ) /__/ / / / __/".bold().cyan()); println!(" {} ", r"/_/ |_|\__,_/____/\___/_/ /_/\___/ ".bold().cyan()); println!("\n{}", "To exit, press Ctrl + D.".dimmed()); }