use std::io::Write; use crate::error::LoxError; use crate::interpreter::eval::execute; use crate::interpreter::Value; 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(); if let Err(err) = run(&source_code, &mut env) { 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(); let mut env = Environment::new(); '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; } */ 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, &mut env) { Ok(()) => {} 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)?; // println!("{expr}"); // let mut result = Value::Nil; for statement in statements { execute(statement, env)?; } /* match result { Value::Nil => {} result => println!("{result}"), } */ Ok(()) }