use std::io::Write; use crate::error::LoxError; use crate::interpreter::eval::evaluate; use crate::lexer::{scan_tokens, Token}; use crate::parser::parser::parse_tokens; pub fn interpreter_main() { let args: Vec = std::env::args().collect(); match args.len() { 1 => run_repl(), 2 => run_file(&args[1]), _ => { eprintln!("Usage: rlox [script]"); std::process::exit(64); } } } fn run_file(script_path: &str) { let source_code = std::fs::read_to_string(script_path).unwrap_or_else(|err| { eprintln!("Reading script file {} failed: {}", script_path, err); std::process::exit(66); }); /* if let Err(err) = run(&source_code) { eprintln!("{}", err); std::process::exit(65); } */ if let Err(err) = run(&source_code) { eprintln!("{err}"); match err { LoxError::LexerError { .. } | LoxError::ParserError { .. } => std::process::exit(65), LoxError::EvalError { .. } => std::process::exit(70), } } } fn run_repl() { let stdin = std::io::stdin(); 'outer: loop { let mut input_buf = String::new(); print!("> "); std::io::stdout().flush().unwrap(); 'inner: loop { stdin.read_line(&mut input_buf).unwrap_or_else(|err| { eprintln!("Could not read from stdin: {}", err); std::process::exit(66); }); let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); let num_open_parens = (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); let num_open_brackets = (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); // all braces/parens/brackets closed => break if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 { break 'inner; } // any braces/parens/brackets more closing than opening => break (will be parse error) if num_open_braces < 0 || num_open_parens < 0 || num_open_brackets < 0 { break 'inner; } print!("< "); std::io::stdout().flush().unwrap(); } input_buf = input_buf.trim().to_owned(); if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" { break 'outer; } match run(&input_buf) { Ok(()) => {} Err(err) => eprintln!("{}", err), } } } fn run(code_string: &str) -> Result<(), LoxError> { let tokens: Vec = scan_tokens(code_string)?; /* let token_str = tokens .iter() .map(|token| format!("{token}")) .collect::>() .join(" "); println!("{token_str}"); */ let expr = parse_tokens(tokens)?; println!("{expr}"); let result = evaluate(expr)?; println!("{result}"); Ok(()) }