2023-01-20 16:10:03 +01:00
|
|
|
use std::io::Write;
|
|
|
|
|
|
|
|
|
|
use crate::error::LoxError;
|
2023-01-25 19:01:13 +01:00
|
|
|
use crate::interpreter::interpret::execute;
|
2023-01-20 16:10:03 +01:00
|
|
|
use crate::lexer::{scan_tokens, Token};
|
2023-01-22 23:33:57 +01:00
|
|
|
use crate::parser::parse_tokens;
|
|
|
|
|
|
|
|
|
|
use super::environment::Environment;
|
2023-01-20 16:10:03 +01:00
|
|
|
|
|
|
|
|
pub fn interpreter_main() {
|
|
|
|
|
let args: Vec<String> = 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);
|
|
|
|
|
});
|
|
|
|
|
|
2023-01-20 21:44:27 +01:00
|
|
|
/* if let Err(err) = run(&source_code) {
|
2023-01-20 16:10:03 +01:00
|
|
|
eprintln!("{}", err);
|
|
|
|
|
std::process::exit(65);
|
2023-01-20 21:44:27 +01:00
|
|
|
} */
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
let mut env = Environment::new();
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
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),
|
|
|
|
|
}
|
2023-01-20 21:44:27 +01:00
|
|
|
}
|
2023-01-20 16:10:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run_repl() {
|
|
|
|
|
let stdin = std::io::stdin();
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
let mut env = Environment::new();
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
loop {
|
2023-01-20 16:10:03 +01:00
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64);
|
2023-01-20 16:10:03 +01:00
|
|
|
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;
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
2023-01-20 16:10:03 +01:00
|
|
|
|
|
|
|
|
print!("< ");
|
|
|
|
|
std::io::stdout().flush().unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
let input_buf = input_buf.trim();
|
2023-01-20 16:10:03 +01:00
|
|
|
|
|
|
|
|
if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" {
|
2023-01-25 19:01:13 +01:00
|
|
|
std::process::exit(0);
|
2023-01-20 16:10:03 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
match run(input_buf, &mut env) {
|
2023-01-20 16:10:03 +01:00
|
|
|
Ok(()) => {}
|
2023-01-25 19:01:13 +01:00
|
|
|
Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code),
|
2023-01-20 16:10:03 +01:00
|
|
|
Err(err) => eprintln!("{}", err),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
fn run(code_string: &str, env: &mut Environment) -> Result<(), LoxError> {
|
2023-01-20 16:10:03 +01:00
|
|
|
let tokens: Vec<Token> = scan_tokens(code_string)?;
|
|
|
|
|
|
|
|
|
|
/* let token_str = tokens
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|token| format!("{token}"))
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
.join(" ");
|
|
|
|
|
|
|
|
|
|
println!("{token_str}"); */
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
let statements = parse_tokens(tokens)?;
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
/* for statement in statements.iter() {
|
|
|
|
|
println!("{statement}");
|
|
|
|
|
} */
|
2023-01-20 16:10:03 +01:00
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
// let mut result = Value::Nil;
|
2023-01-20 16:10:03 +01:00
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
for statement in statements {
|
|
|
|
|
execute(statement, env)?;
|
|
|
|
|
}
|
2023-01-20 21:44:27 +01:00
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
/* match result {
|
|
|
|
|
Value::Nil => {}
|
|
|
|
|
result => println!("{result}"),
|
|
|
|
|
} */
|
2023-01-20 21:44:27 +01:00
|
|
|
|
2023-01-20 16:10:03 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|