use std::io::Write; use crate::error::LoxError; use crate::interpreter::interpret::execute; use crate::lexer::{scan_tokens, Token}; use crate::parser::parse_tokens; use super::environment::Environment; 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); } */ let mut env = Environment::new(); match run(&source_code, &mut env) { Ok(()) => std::process::exit(0), Err(err) => { eprintln!("{err}"); match err { LoxError::LexerError { .. } | LoxError::ParserError { .. } => std::process::exit(65), LoxError::RuntimeError { .. } => std::process::exit(70), LoxError::Exit { exit_code } => std::process::exit(exit_code), } } } } fn run_repl() { let stdin = std::io::stdin(); let mut env = Environment::new(); 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(); } let input_buf = input_buf.trim(); if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" { std::process::exit(0); } match run(input_buf, &mut env) { Ok(()) => {} Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code), Err(err) => eprintln!("{}", err), } } } fn run(code_string: &str, env: &mut Environment) -> Result<(), LoxError> { let tokens: Vec = scan_tokens(code_string)?; /* let token_str = tokens .iter() .map(|token| format!("{token}")) .collect::>() .join(" "); println!("{token_str}"); */ let statements = parse_tokens(tokens)?; /* for statement in statements.iter() { println!("{statement}"); } */ // let mut result = Value::Nil; for statement in statements { execute(statement, env)?; } /* match result { Value::Nil => {} result => println!("{result}"), } */ Ok(()) }